Convert mask type to enum
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blob19132109bda6cc829a8ed29e4187bde5a9f7fe3a
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 "gui-pinout-preview.h"
13 /* The Linux OpenGL ABI 1.0 spec requires that we define
14 * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions
15 * in order to get prototypes:
16 * http://www.opengl.org/registry/ABI/
19 #define GL_GLEXT_PROTOTYPES 1
20 #ifdef HAVE_OPENGL_GL_H
21 # include <OpenGL/gl.h>
22 #else
23 # include <GL/gl.h>
24 #endif
26 #include <gtk/gtkgl.h>
27 #include "hid/common/hidgl.h"
29 #include "hid/common/draw_helpers.h"
30 #include "hid/common/trackball.h"
32 #ifdef HAVE_LIBDMALLOC
33 #include <dmalloc.h>
34 #endif
36 extern HID ghid_hid;
38 static hidGC current_gc = NULL;
40 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
42 #define USE_GC(gc) if (!use_gc(gc)) return
44 static enum mask_mode cur_mask = HID_MASK_OFF;
45 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
46 {0.0, 1.0, 0.0, 0.0},
47 {0.0, 0.0, 1.0, 0.0},
48 {0.0, 0.0, 0.0, 1.0}};
49 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
50 {0.0, 1.0, 0.0, 0.0},
51 {0.0, 0.0, 1.0, 0.0},
52 {0.0, 0.0, 0.0, 1.0}};
53 static int global_view_2d = 1;
55 typedef struct render_priv {
56 GdkGLConfig *glconfig;
57 bool trans_lines;
58 bool in_context;
59 int subcomposite_stencil_bit;
60 char *current_colorname;
61 double current_alpha_mult;
62 GTimer *time_since_expose;
64 /* Feature for leading the user to a particular location */
65 guint lead_user_timeout;
66 GTimer *lead_user_timer;
67 bool lead_user;
68 Coord lead_user_radius;
69 Coord lead_user_x;
70 Coord lead_user_y;
72 } render_priv;
75 typedef struct hid_gc_struct
77 HID *me_pointer;
79 const char *colorname;
80 double alpha_mult;
81 Coord width;
82 gint cap, join;
84 hid_gc_struct;
87 static void draw_lead_user (render_priv *priv);
88 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
91 static void
92 start_subcomposite (void)
94 render_priv *priv = gport->render_priv;
95 int stencil_bit;
97 /* Flush out any existing geoemtry to be rendered */
98 hidgl_flush_triangles (&buffer);
100 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
101 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
103 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
104 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
105 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
107 priv->subcomposite_stencil_bit = stencil_bit;
110 static void
111 end_subcomposite (void)
113 render_priv *priv = gport->render_priv;
115 /* Flush out any existing geoemtry to be rendered */
116 hidgl_flush_triangles (&buffer);
118 hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
120 glStencilMask (0);
121 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
122 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
124 priv->subcomposite_stencil_bit = 0;
129 ghid_set_layer (const char *name, int group, int empty)
131 render_priv *priv = gport->render_priv;
132 int idx = group;
133 if (idx >= 0 && idx < max_group)
135 int n = PCB->LayerGroups.Number[group];
136 for (idx = 0; idx < n-1; idx ++)
138 int ni = PCB->LayerGroups.Entries[group][idx];
139 if (ni >= 0 && ni < max_copper_layer + 2
140 && PCB->Data->Layer[ni].On)
141 break;
143 idx = PCB->LayerGroups.Entries[group][idx];
146 end_subcomposite ();
147 start_subcomposite ();
149 if (idx >= 0 && idx < max_copper_layer + 2)
151 priv->trans_lines = true;
152 return PCB->Data->Layer[idx].On;
154 if (idx < 0)
156 switch (SL_TYPE (idx))
158 case SL_INVISIBLE:
159 return PCB->InvisibleObjectsOn;
160 case SL_MASK:
161 if (SL_MYSIDE (idx))
162 return TEST_FLAG (SHOWMASKFLAG, PCB);
163 return 0;
164 case SL_SILK:
165 priv->trans_lines = true;
166 if (SL_MYSIDE (idx))
167 return PCB->ElementOn;
168 return 0;
169 case SL_ASSY:
170 return 0;
171 case SL_PDRILL:
172 case SL_UDRILL:
173 return 1;
174 case SL_RATS:
175 if (PCB->RatOn)
176 priv->trans_lines = true;
177 return PCB->RatOn;
180 return 0;
183 static void
184 ghid_end_layer (void)
186 end_subcomposite ();
189 void
190 ghid_destroy_gc (hidGC gc)
192 g_free (gc);
195 hidGC
196 ghid_make_gc (void)
198 hidGC rv;
200 rv = g_new0 (hid_gc_struct, 1);
201 rv->me_pointer = &ghid_hid;
202 rv->colorname = Settings.BackgroundColor;
203 rv->alpha_mult = 1.0;
204 return rv;
207 static void
208 ghid_draw_grid (BoxType *drawn_area)
210 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
211 return;
213 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
215 gport->grid_color.red ^= gport->bg_color.red;
216 gport->grid_color.green ^= gport->bg_color.green;
217 gport->grid_color.blue ^= gport->bg_color.blue;
220 glEnable (GL_COLOR_LOGIC_OP);
221 glLogicOp (GL_XOR);
223 glColor3f (gport->grid_color.red / 65535.,
224 gport->grid_color.green / 65535.,
225 gport->grid_color.blue / 65535.);
227 hidgl_draw_grid (drawn_area);
229 glDisable (GL_COLOR_LOGIC_OP);
232 static void
233 ghid_draw_bg_image (void)
235 static GLuint texture_handle = 0;
237 if (!ghidgui->bg_pixbuf)
238 return;
240 if (texture_handle == 0)
242 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
243 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
244 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
245 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
246 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
247 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
249 g_warn_if_fail (bits_per_sample == 8);
250 g_warn_if_fail (rowstride == width * n_channels);
252 glGenTextures (1, &texture_handle);
253 glBindTexture (GL_TEXTURE_2D, texture_handle);
255 /* XXX: We should proabbly determine what the maxmimum texture supported is,
256 * and if our image is larger, shrink it down using GDK pixbuf routines
257 * rather than having it fail below.
260 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
261 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
264 glBindTexture (GL_TEXTURE_2D, texture_handle);
266 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
267 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
268 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
269 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
270 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
271 glEnable (GL_TEXTURE_2D);
273 /* Render a quad with the background as a texture */
275 glBegin (GL_QUADS);
276 glTexCoord2d (0., 0.);
277 glVertex3i (0, 0, 0);
278 glTexCoord2d (1., 0.);
279 glVertex3i (PCB->MaxWidth, 0, 0);
280 glTexCoord2d (1., 1.);
281 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
282 glTexCoord2d (0., 1.);
283 glVertex3i (0, PCB->MaxHeight, 0);
284 glEnd ();
286 glDisable (GL_TEXTURE_2D);
289 void
290 ghid_use_mask (enum mask_mode mode)
292 static int stencil_bit = 0;
294 if (mode == cur_mask)
295 return;
297 /* Flush out any existing geoemtry to be rendered */
298 hidgl_flush_triangles (&buffer);
300 switch (mode)
302 case HID_MASK_BEFORE:
303 /* The HID asks not to receive this mask type, so warn if we get it */
304 g_return_if_reached ();
306 case HID_MASK_CLEAR:
307 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
308 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
309 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
310 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
311 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
312 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
313 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
314 break;
316 case HID_MASK_AFTER:
317 /* Drawing operations as masked to areas where the stencil buffer is '0' */
318 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
319 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
320 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
321 break;
323 case HID_MASK_OFF:
324 /* Disable stenciling */
325 hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */
326 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
327 break;
329 cur_mask = mode;
333 /* Config helper functions for when the user changes color preferences.
334 | set_special colors used in the gtkhid.
336 static void
337 set_special_grid_color (void)
339 if (!gport->colormap)
340 return;
341 gport->grid_color.red ^= gport->bg_color.red;
342 gport->grid_color.green ^= gport->bg_color.green;
343 gport->grid_color.blue ^= gport->bg_color.blue;
346 void
347 ghid_set_special_colors (HID_Attribute * ha)
349 if (!ha->name || !ha->value)
350 return;
351 if (!strcmp (ha->name, "background-color"))
353 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
354 set_special_grid_color ();
356 else if (!strcmp (ha->name, "off-limit-color"))
358 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
360 else if (!strcmp (ha->name, "grid-color"))
362 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
363 set_special_grid_color ();
367 typedef struct
369 int color_set;
370 GdkColor color;
371 double red;
372 double green;
373 double blue;
374 } ColorCache;
376 static void
377 set_gl_color_for_gc (hidGC gc)
379 render_priv *priv = gport->render_priv;
380 static void *cache = NULL;
381 hidval cval;
382 ColorCache *cc;
383 double r, g, b, a;
385 if (priv->current_colorname != NULL &&
386 strcmp (priv->current_colorname, gc->colorname) == 0 &&
387 priv->current_alpha_mult == gc->alpha_mult)
388 return;
390 free (priv->current_colorname);
391 priv->current_colorname = strdup (gc->colorname);
392 priv->current_alpha_mult = gc->alpha_mult;
394 if (gport->colormap == NULL)
395 gport->colormap = gtk_widget_get_colormap (gport->top_window);
396 if (strcmp (gc->colorname, "erase") == 0)
398 r = gport->bg_color.red / 65535.;
399 g = gport->bg_color.green / 65535.;
400 b = gport->bg_color.blue / 65535.;
401 a = 1.0;
403 else if (strcmp (gc->colorname, "drill") == 0)
405 r = gport->offlimits_color.red / 65535.;
406 g = gport->offlimits_color.green / 65535.;
407 b = gport->offlimits_color.blue / 65535.;
408 a = 0.85;
410 else
412 if (hid_cache_color (0, gc->colorname, &cval, &cache))
413 cc = (ColorCache *) cval.ptr;
414 else
416 cc = (ColorCache *) malloc (sizeof (ColorCache));
417 memset (cc, 0, sizeof (*cc));
418 cval.ptr = cc;
419 hid_cache_color (1, gc->colorname, &cval, &cache);
422 if (!cc->color_set)
424 if (gdk_color_parse (gc->colorname, &cc->color))
425 gdk_color_alloc (gport->colormap, &cc->color);
426 else
427 gdk_color_white (gport->colormap, &cc->color);
428 cc->red = cc->color.red / 65535.;
429 cc->green = cc->color.green / 65535.;
430 cc->blue = cc->color.blue / 65535.;
431 cc->color_set = 1;
433 r = cc->red;
434 g = cc->green;
435 b = cc->blue;
436 a = 0.7;
438 if (1) {
439 double maxi, mult;
440 a *= gc->alpha_mult;
441 if (!priv->trans_lines)
442 a = 1.0;
443 maxi = r;
444 if (g > maxi) maxi = g;
445 if (b > maxi) maxi = b;
446 mult = MIN (1 / a, 1 / maxi);
447 #if 1
448 r = r * mult;
449 g = g * mult;
450 b = b * mult;
451 #endif
454 if(!priv->in_context)
455 return;
457 hidgl_flush_triangles (&buffer);
458 glColor4d (r, g, b, a);
461 void
462 ghid_set_color (hidGC gc, const char *name)
464 gc->colorname = name;
465 set_gl_color_for_gc (gc);
468 void
469 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
471 gc->alpha_mult = alpha_mult;
472 set_gl_color_for_gc (gc);
475 void
476 ghid_set_line_cap (hidGC gc, EndCapStyle style)
478 gc->cap = style;
481 void
482 ghid_set_line_width (hidGC gc, Coord width)
484 gc->width = width;
488 void
489 ghid_set_draw_xor (hidGC gc, int xor)
491 /* NOT IMPLEMENTED */
493 /* Only presently called when setting up a crosshair GC.
494 * We manage our own drawing model for that anyway. */
497 void
498 ghid_set_draw_faded (hidGC gc, int faded)
500 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
503 void
504 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
506 printf ("ghid_set_line_cap_angle() -- not implemented\n");
509 static void
510 ghid_invalidate_current_gc (void)
512 current_gc = NULL;
515 static int
516 use_gc (hidGC gc)
518 if (gc->me_pointer != &ghid_hid)
520 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
521 abort ();
524 if (current_gc == gc)
525 return 1;
527 current_gc = gc;
529 set_gl_color_for_gc (gc);
530 return 1;
533 void
534 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
536 USE_GC (gc);
538 hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
541 void
542 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
543 Angle start_angle, Angle delta_angle)
545 USE_GC (gc);
547 hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
548 start_angle, delta_angle, gport->view.coord_per_px);
551 void
552 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
554 USE_GC (gc);
556 hidgl_draw_rect (x1, y1, x2, y2);
560 void
561 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
563 USE_GC (gc);
565 hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px);
569 void
570 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
572 USE_GC (gc);
574 hidgl_fill_polygon (n_coords, x, y);
577 void
578 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
580 USE_GC (gc);
582 hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px);
585 void
586 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
588 common_thindraw_pcb_polygon (gc, poly, clip_box);
589 ghid_set_alpha_mult (gc, 0.25);
590 ghid_fill_pcb_polygon (gc, poly, clip_box);
591 ghid_set_alpha_mult (gc, 1.0);
594 void
595 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
597 USE_GC (gc);
599 hidgl_fill_rect (x1, y1, x2, y2);
602 void
603 ghid_invalidate_lr (int left, int right, int top, int bottom)
605 ghid_invalidate_all ();
608 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
609 void
610 ghid_invalidate_all ()
612 render_priv *priv = gport->render_priv;
613 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
615 ghid_draw_area_update (gport, NULL);
617 if (elapsed > MAX_ELAPSED)
618 gdk_window_process_all_updates ();
621 void
622 ghid_notify_crosshair_change (bool changes_complete)
624 /* We sometimes get called before the GUI is up */
625 if (gport->drawing_area == NULL)
626 return;
628 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
629 ghid_invalidate_all ();
632 void
633 ghid_notify_mark_change (bool changes_complete)
635 /* We sometimes get called before the GUI is up */
636 if (gport->drawing_area == NULL)
637 return;
639 /* FIXME: We could just invalidate the bounds of the mark? */
640 ghid_invalidate_all ();
643 static void
644 draw_right_cross (gint x, gint y, gint z)
646 glVertex3i (x, 0, z);
647 glVertex3i (x, PCB->MaxHeight, z);
648 glVertex3i (0, y, z);
649 glVertex3i (PCB->MaxWidth, y, z);
652 static void
653 draw_slanted_cross (gint x, gint y, gint z)
655 gint x0, y0, x1, y1;
657 x0 = x + (PCB->MaxHeight - y);
658 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
659 x1 = x - y;
660 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
661 y0 = y + (PCB->MaxWidth - x);
662 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
663 y1 = y - x;
664 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
665 glVertex3i (x0, y0, z);
666 glVertex3i (x1, y1, z);
668 x0 = x - (PCB->MaxHeight - y);
669 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
670 x1 = x + y;
671 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
672 y0 = y + x;
673 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
674 y1 = y - (PCB->MaxWidth - x);
675 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
676 glVertex3i (x0, y0, z);
677 glVertex3i (x1, y1, z);
680 static void
681 draw_dozen_cross (gint x, gint y, gint z)
683 gint x0, y0, x1, y1;
684 gdouble tan60 = sqrt (3);
686 x0 = x + (PCB->MaxHeight - y) / tan60;
687 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
688 x1 = x - y / tan60;
689 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
690 y0 = y + (PCB->MaxWidth - x) * tan60;
691 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
692 y1 = y - x * tan60;
693 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
694 glVertex3i (x0, y0, z);
695 glVertex3i (x1, y1, z);
697 x0 = x + (PCB->MaxHeight - y) * tan60;
698 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
699 x1 = x - y * tan60;
700 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
701 y0 = y + (PCB->MaxWidth - x) / tan60;
702 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
703 y1 = y - x / tan60;
704 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
705 glVertex3i (x0, y0, z);
706 glVertex3i (x1, y1, z);
708 x0 = x - (PCB->MaxHeight - y) / tan60;
709 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
710 x1 = x + y / tan60;
711 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
712 y0 = y + x * tan60;
713 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
714 y1 = y - (PCB->MaxWidth - x) * tan60;
715 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
716 glVertex3i (x0, y0, z);
717 glVertex3i (x1, y1, z);
719 x0 = x - (PCB->MaxHeight - y) * tan60;
720 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
721 x1 = x + y * tan60;
722 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
723 y0 = y + x / tan60;
724 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
725 y1 = y - (PCB->MaxWidth - x) / tan60;
726 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
727 glVertex3i (x0, y0, z);
728 glVertex3i (x1, y1, z);
731 static void
732 draw_crosshair (render_priv *priv)
734 gint x, y, z;
735 static int done_once = 0;
736 static GdkColor cross_color;
738 if (!done_once)
740 done_once = 1;
741 /* FIXME: when CrossColor changed from config */
742 ghid_map_color_string (Settings.CrossColor, &cross_color);
745 x = gport->crosshair_x;
746 y = gport->crosshair_y;
747 z = 0;
749 glEnable (GL_COLOR_LOGIC_OP);
750 glLogicOp (GL_XOR);
752 glColor3f (cross_color.red / 65535.,
753 cross_color.green / 65535.,
754 cross_color.blue / 65535.);
756 glBegin (GL_LINES);
758 draw_right_cross (x, y, z);
759 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
760 draw_slanted_cross (x, y, z);
761 if (Crosshair.shape == Dozen_Crosshair_Shape)
762 draw_dozen_cross (x, y, z);
764 glEnd ();
766 glDisable (GL_COLOR_LOGIC_OP);
769 void
770 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
772 render_priv *priv;
774 port->render_priv = priv = g_new0 (render_priv, 1);
776 priv->time_since_expose = g_timer_new ();
778 gtk_gl_init(argc, argv);
780 /* setup GL-context */
781 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
782 GDK_GL_MODE_STENCIL |
783 GDK_GL_MODE_DOUBLE);
784 if (!priv->glconfig)
786 printf ("Could not setup GL-context!\n");
787 return; /* Should we abort? */
790 /* Setup HID function pointers specific to the GL renderer*/
791 ghid_hid.end_layer = ghid_end_layer;
792 ghid_hid.fill_pcb_polygon = ghid_fill_pcb_polygon;
793 ghid_hid.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
796 void
797 ghid_shutdown_renderer (GHidPort *port)
799 ghid_cancel_lead_user ();
800 g_free (port->render_priv);
801 port->render_priv = NULL;
804 void
805 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
807 render_priv *priv = port->render_priv;
809 gtk_widget_set_gl_capability (widget,
810 priv->glconfig,
811 NULL,
812 TRUE,
813 GDK_GL_RGBA_TYPE);
816 void
817 ghid_drawing_area_configure_hook (GHidPort *port)
821 gboolean
822 ghid_start_drawing (GHidPort *port)
824 GtkWidget *widget = port->drawing_area;
825 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
826 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
828 /* make GL-context "current" */
829 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
830 return FALSE;
832 port->render_priv->in_context = true;
834 return TRUE;
837 void
838 ghid_end_drawing (GHidPort *port)
840 GtkWidget *widget = port->drawing_area;
841 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
843 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
844 gdk_gl_drawable_swap_buffers (pGlDrawable);
845 else
846 glFlush ();
848 port->render_priv->in_context = false;
850 /* end drawing to current GL-context */
851 gdk_gl_drawable_gl_end (pGlDrawable);
854 void
855 ghid_screen_update (void)
859 #define Z_NEAR 3.0
860 gboolean
861 ghid_drawing_area_expose_cb (GtkWidget *widget,
862 GdkEventExpose *ev,
863 GHidPort *port)
865 render_priv *priv = port->render_priv;
866 GtkAllocation allocation;
867 BoxType region;
868 Coord min_x, min_y;
869 Coord max_x, max_y;
870 Coord new_x, new_y;
871 Coord min_depth;
872 Coord max_depth;
874 gtk_widget_get_allocation (widget, &allocation);
876 ghid_start_drawing (port);
877 hidgl_start_render ();
879 /* If we don't have any stencil bits available,
880 we can't use the hidgl polygon drawing routine */
881 /* TODO: We could use the GLU tessellator though */
882 if (hidgl_stencil_bits() == 0)
883 ghid_hid.fill_pcb_polygon = common_fill_pcb_polygon;
885 glEnable (GL_BLEND);
886 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
888 glViewport (0, 0, allocation.width, allocation.height);
890 glEnable (GL_SCISSOR_TEST);
891 glScissor (ev->area.x,
892 allocation.height - ev->area.height - ev->area.y,
893 ev->area.width, ev->area.height);
895 glMatrixMode (GL_PROJECTION);
896 glLoadIdentity ();
897 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
898 glMatrixMode (GL_MODELVIEW);
899 glLoadIdentity ();
900 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
901 glMultMatrixf ((GLfloat *)view_matrix);
902 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
903 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
904 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
905 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
906 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
907 -port->view.x0,
908 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
909 -port->view.y0, 0);
910 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
912 glEnable (GL_STENCIL_TEST);
913 glClearColor (port->offlimits_color.red / 65535.,
914 port->offlimits_color.green / 65535.,
915 port->offlimits_color.blue / 65535.,
916 1.);
917 glStencilMask (~0);
918 glClearStencil (0);
919 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
920 hidgl_reset_stencil_usage ();
922 /* Disable the stencil test until we need it - otherwise it gets dirty */
923 glDisable (GL_STENCIL_TEST);
924 glStencilMask (0);
925 glStencilFunc (GL_ALWAYS, 0, 0);
927 /* Test the 8 corners of a cube spanning the event */
928 min_depth = -50; /* FIXME */
929 max_depth = 0; /* FIXME */
931 ghid_unproject_to_z_plane (ev->area.x,
932 ev->area.y,
933 min_depth, &new_x, &new_y);
934 max_x = min_x = new_x;
935 max_y = min_y = new_y;
937 ghid_unproject_to_z_plane (ev->area.x,
938 ev->area.y,
939 max_depth, &new_x, &new_y);
940 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
941 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
943 /* */
944 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
945 ev->area.y,
946 min_depth, &new_x, &new_y);
947 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
948 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
950 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
951 max_depth, &new_x, &new_y);
952 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
953 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
955 /* */
956 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
957 ev->area.y + ev->area.height,
958 min_depth, &new_x, &new_y);
959 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
960 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
962 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
963 ev->area.y + ev->area.height,
964 max_depth, &new_x, &new_y);
965 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
966 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
968 /* */
969 ghid_unproject_to_z_plane (ev->area.x,
970 ev->area.y + ev->area.height,
971 min_depth,
972 &new_x, &new_y);
973 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
974 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
976 ghid_unproject_to_z_plane (ev->area.x,
977 ev->area.y + ev->area.height,
978 max_depth,
979 &new_x, &new_y);
980 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
981 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
983 region.X1 = min_x; region.X2 = max_x + 1;
984 region.Y1 = min_y; region.Y2 = max_y + 1;
986 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
987 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
988 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
989 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
991 glColor3f (port->bg_color.red / 65535.,
992 port->bg_color.green / 65535.,
993 port->bg_color.blue / 65535.);
995 glBegin (GL_QUADS);
996 glVertex3i (0, 0, -50);
997 glVertex3i (PCB->MaxWidth, 0, -50);
998 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
999 glVertex3i (0, PCB->MaxHeight, -50);
1000 glEnd ();
1002 ghid_draw_bg_image ();
1004 ghid_invalidate_current_gc ();
1005 hid_expose_callback (&ghid_hid, &region, 0);
1006 hidgl_flush_triangles (&buffer);
1008 ghid_draw_grid (&region);
1010 ghid_invalidate_current_gc ();
1012 DrawAttached ();
1013 DrawMark ();
1014 hidgl_flush_triangles (&buffer);
1016 draw_crosshair (priv);
1017 hidgl_flush_triangles (&buffer);
1019 draw_lead_user (priv);
1021 hidgl_finish_render ();
1022 ghid_end_drawing (port);
1024 g_timer_start (priv->time_since_expose);
1026 return FALSE;
1029 /* This realize callback is used to work around a crash bug in some mesa
1030 * versions (observed on a machine running the intel i965 driver. It isn't
1031 * obvious why it helps, but somehow fiddling with the GL context here solves
1032 * the issue. The problem appears to have been fixed in recent mesa versions.
1034 void
1035 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1037 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1038 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1040 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1041 return;
1043 gdk_gl_drawable_gl_end (gldrawable);
1044 return;
1047 gboolean
1048 ghid_pinout_preview_expose (GtkWidget *widget,
1049 GdkEventExpose *ev)
1051 GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
1052 GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
1053 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
1054 GtkAllocation allocation;
1055 view_data save_view;
1056 int save_width, save_height;
1057 Coord save_max_width;
1058 Coord save_max_height;
1059 double xz, yz;
1061 save_view = gport->view;
1062 save_width = gport->width;
1063 save_height = gport->height;
1064 save_max_width = PCB->MaxWidth;
1065 save_max_height = PCB->MaxHeight;
1067 /* Setup zoom factor for drawing routines */
1069 gtk_widget_get_allocation (widget, &allocation);
1070 xz = (double) pinout->x_max / allocation.width;
1071 yz = (double) pinout->y_max / allocation.height;
1072 if (xz > yz)
1073 gport->view.coord_per_px = xz;
1074 else
1075 gport->view.coord_per_px = yz;
1077 gport->width = allocation.width;
1078 gport->height = allocation.height;
1079 gport->view.width = allocation.width * gport->view.coord_per_px;
1080 gport->view.height = allocation.height * gport->view.coord_per_px;
1081 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
1082 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
1083 PCB->MaxWidth = pinout->x_max;
1084 PCB->MaxHeight = pinout->y_max;
1086 /* make GL-context "current" */
1087 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
1088 return FALSE;
1090 hidgl_start_render ();
1091 gport->render_priv->in_context = true;
1093 glEnable (GL_BLEND);
1094 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1096 glViewport (0, 0, allocation.width, allocation.height);
1098 glEnable (GL_SCISSOR_TEST);
1099 glScissor (ev->area.x,
1100 allocation.height - ev->area.height - ev->area.y,
1101 ev->area.width, ev->area.height);
1103 glMatrixMode (GL_PROJECTION);
1104 glLoadIdentity ();
1105 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1106 glMatrixMode (GL_MODELVIEW);
1107 glLoadIdentity ();
1108 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1110 glClearColor (gport->bg_color.red / 65535.,
1111 gport->bg_color.green / 65535.,
1112 gport->bg_color.blue / 65535.,
1113 1.);
1114 glStencilMask (~0);
1115 glClearStencil (0);
1116 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1117 hidgl_reset_stencil_usage ();
1119 /* call the drawing routine */
1120 ghid_invalidate_current_gc ();
1121 glPushMatrix ();
1122 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1123 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1124 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1125 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1126 -gport->view.x0,
1127 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1128 -gport->view.y0, 0);
1130 hid_expose_callback (&ghid_hid, NULL, &pinout->element);
1131 hidgl_flush_triangles (&buffer);
1132 glPopMatrix ();
1134 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1135 gdk_gl_drawable_swap_buffers (pGlDrawable);
1136 else
1137 glFlush ();
1139 hidgl_finish_render ();
1141 /* end drawing to current GL-context */
1142 gport->render_priv->in_context = false;
1143 gdk_gl_drawable_gl_end (pGlDrawable);
1145 gport->view = save_view;
1146 gport->width = save_width;
1147 gport->height = save_height;
1148 PCB->MaxWidth = save_max_width;
1149 PCB->MaxHeight = save_max_height;
1151 return FALSE;
1155 GdkPixmap *
1156 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
1158 GdkGLConfig *glconfig;
1159 GdkPixmap *pixmap;
1160 GdkGLPixmap *glpixmap;
1161 GdkGLContext* glcontext;
1162 GdkGLDrawable* gldrawable;
1163 view_data save_view;
1164 int save_width, save_height;
1165 BoxType region;
1167 save_view = gport->view;
1168 save_width = gport->width;
1169 save_height = gport->height;
1171 /* Setup rendering context for drawing routines
1174 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
1175 GDK_GL_MODE_STENCIL |
1176 GDK_GL_MODE_SINGLE);
1178 pixmap = gdk_pixmap_new (NULL, width, height, depth);
1179 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
1180 gldrawable = GDK_GL_DRAWABLE (glpixmap);
1181 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
1183 /* Setup zoom factor for drawing routines */
1185 gport->view.coord_per_px = zoom;
1186 gport->width = width;
1187 gport->height = height;
1188 gport->view.width = width * gport->view.coord_per_px;
1189 gport->view.height = height * gport->view.coord_per_px;
1190 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
1191 gport->view.x0 -= gport->view.height / 2;
1192 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
1193 gport->view.y0 -= gport->view.width / 2;
1195 /* make GL-context "current" */
1196 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
1197 return NULL;
1199 hidgl_start_render ();
1200 gport->render_priv->in_context = true;
1202 glEnable (GL_BLEND);
1203 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1205 glViewport (0, 0, width, height);
1207 glEnable (GL_SCISSOR_TEST);
1208 glScissor (0, 0, width, height);
1210 glMatrixMode (GL_PROJECTION);
1211 glLoadIdentity ();
1212 glOrtho (0, width, height, 0, -100000, 100000);
1213 glMatrixMode (GL_MODELVIEW);
1214 glLoadIdentity ();
1215 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1217 glClearColor (gport->bg_color.red / 65535.,
1218 gport->bg_color.green / 65535.,
1219 gport->bg_color.blue / 65535.,
1220 1.);
1221 glStencilMask (~0);
1222 glClearStencil (0);
1223 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1224 hidgl_reset_stencil_usage ();
1226 /* call the drawing routine */
1227 ghid_invalidate_current_gc ();
1228 glPushMatrix ();
1229 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1230 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1231 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1232 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1233 -gport->view.x0,
1234 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1235 -gport->view.y0, 0);
1237 region.X1 = MIN(Px(0), Px(gport->width + 1));
1238 region.Y1 = MIN(Py(0), Py(gport->height + 1));
1239 region.X2 = MAX(Px(0), Px(gport->width + 1));
1240 region.Y2 = MAX(Py(0), Py(gport->height + 1));
1242 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1243 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1244 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1245 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1247 hid_expose_callback (&ghid_hid, &region, NULL);
1248 hidgl_flush_triangles (&buffer);
1249 glPopMatrix ();
1251 glFlush ();
1253 hidgl_finish_render ();
1255 /* end drawing to current GL-context */
1256 gport->render_priv->in_context = false;
1257 gdk_gl_drawable_gl_end (gldrawable);
1259 gdk_pixmap_unset_gl_capability (pixmap);
1261 g_object_unref (glconfig);
1262 g_object_unref (glcontext);
1264 gport->view = save_view;
1265 gport->width = save_width;
1266 gport->height = save_height;
1268 return pixmap;
1271 HID *
1272 ghid_request_debug_draw (void)
1274 GHidPort *port = gport;
1275 GtkWidget *widget = port->drawing_area;
1276 GtkAllocation allocation;
1278 gtk_widget_get_allocation (widget, &allocation);
1280 ghid_start_drawing (port);
1281 hidgl_start_render ();
1283 glViewport (0, 0, allocation.width, allocation.height);
1285 glMatrixMode (GL_PROJECTION);
1286 glLoadIdentity ();
1287 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
1288 glMatrixMode (GL_MODELVIEW);
1289 glLoadIdentity ();
1290 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1292 ghid_invalidate_current_gc ();
1294 /* Setup stenciling */
1295 glDisable (GL_STENCIL_TEST);
1297 glPushMatrix ();
1298 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1299 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1300 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1301 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1302 -port->view.x0,
1303 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1304 -port->view.y0, 0);
1306 return &ghid_hid;
1309 void
1310 ghid_flush_debug_draw (void)
1312 GtkWidget *widget = gport->drawing_area;
1313 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1315 hidgl_flush_triangles (&buffer);
1317 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1318 gdk_gl_drawable_swap_buffers (pGlDrawable);
1319 else
1320 glFlush ();
1323 void
1324 ghid_finish_debug_draw (void)
1326 hidgl_flush_triangles (&buffer);
1327 glPopMatrix ();
1329 hidgl_finish_render ();
1330 ghid_end_drawing (gport);
1333 static float
1334 determinant_2x2 (float m[2][2])
1336 float det;
1337 det = m[0][0] * m[1][1] -
1338 m[0][1] * m[1][0];
1339 return det;
1342 #if 0
1343 static float
1344 determinant_4x4 (float m[4][4])
1346 float det;
1347 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] -
1348 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
1349 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
1350 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
1351 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
1352 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
1353 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
1354 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
1355 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
1356 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
1357 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
1358 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
1359 return det;
1361 #endif
1363 static void
1364 invert_2x2 (float m[2][2], float out[2][2])
1366 float scale = 1 / determinant_2x2 (m);
1367 out[0][0] = m[1][1] * scale;
1368 out[0][1] = -m[0][1] * scale;
1369 out[1][0] = -m[1][0] * scale;
1370 out[1][1] = m[0][0] * scale;
1373 #if 0
1374 static void
1375 invert_4x4 (float m[4][4], float out[4][4])
1377 float scale = 1 / determinant_4x4 (m);
1379 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
1380 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
1381 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
1382 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
1383 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
1384 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
1385 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
1386 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
1387 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
1388 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
1389 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
1390 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
1391 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
1392 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
1393 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
1394 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
1395 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
1396 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
1397 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
1398 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
1399 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
1400 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
1401 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
1402 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
1403 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
1404 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
1405 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
1406 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
1407 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
1408 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
1409 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
1410 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
1411 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
1412 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
1413 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
1414 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
1415 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
1416 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
1417 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
1418 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
1419 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
1420 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
1421 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
1422 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
1423 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
1424 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
1425 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
1426 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
1428 #endif
1431 static void
1432 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
1434 float mat[2][2];
1435 float inv_mat[2][2];
1436 float x, y;
1439 ex = view_matrix[0][0] * vx +
1440 view_matrix[0][1] * vy +
1441 view_matrix[0][2] * vz +
1442 view_matrix[0][3] * 1;
1443 ey = view_matrix[1][0] * vx +
1444 view_matrix[1][1] * vy +
1445 view_matrix[1][2] * vz +
1446 view_matrix[1][3] * 1;
1447 UNKNOWN ez = view_matrix[2][0] * vx +
1448 view_matrix[2][1] * vy +
1449 view_matrix[2][2] * vz +
1450 view_matrix[2][3] * 1;
1452 ex - view_matrix[0][3] * 1
1453 - view_matrix[0][2] * vz
1454 = view_matrix[0][0] * vx +
1455 view_matrix[0][1] * vy;
1457 ey - view_matrix[1][3] * 1
1458 - view_matrix[1][2] * vz
1459 = view_matrix[1][0] * vx +
1460 view_matrix[1][1] * vy;
1463 /* NB: last_modelview_matrix is transposed in memory! */
1464 x = (float)ex - last_modelview_matrix[3][0] * 1
1465 - last_modelview_matrix[2][0] * pcb_z;
1467 y = (float)ey - last_modelview_matrix[3][1] * 1
1468 - last_modelview_matrix[2][1] * pcb_z;
1471 x = view_matrix[0][0] * vx +
1472 view_matrix[0][1] * vy;
1474 y = view_matrix[1][0] * vx +
1475 view_matrix[1][1] * vy;
1477 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1478 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1481 mat[0][0] = last_modelview_matrix[0][0];
1482 mat[0][1] = last_modelview_matrix[1][0];
1483 mat[1][0] = last_modelview_matrix[0][1];
1484 mat[1][1] = last_modelview_matrix[1][1];
1486 /* if (determinant_2x2 (mat) < 0.00001) */
1487 /* printf ("Determinant is quite small\n"); */
1489 invert_2x2 (mat, inv_mat);
1491 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
1492 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
1496 bool
1497 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
1499 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
1501 return true;
1504 bool
1505 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
1507 /* NB: last_modelview_matrix is transposed in memory */
1508 float w = last_modelview_matrix[0][3] * (float)pcb_x +
1509 last_modelview_matrix[1][3] * (float)pcb_y +
1510 last_modelview_matrix[2][3] * 0. +
1511 last_modelview_matrix[3][3] * 1.;
1513 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
1514 last_modelview_matrix[1][0] * (float)pcb_y +
1515 last_modelview_matrix[2][0] * 0. +
1516 last_modelview_matrix[3][0] * 1.) / w;
1517 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
1518 last_modelview_matrix[1][1] * (float)pcb_y +
1519 last_modelview_matrix[2][1] * 0. +
1520 last_modelview_matrix[3][1] * 1.) / w;
1522 return true;
1525 void
1526 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
1528 global_view_2d = view_2d;
1529 ghid_invalidate_all ();
1532 void
1533 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
1535 #ifdef DEBUG_ROTATE
1536 int row, column;
1537 #endif
1539 build_rotmatrix (view_matrix, quarternion);
1541 #ifdef DEBUG_ROTATE
1542 for (row = 0; row < 4; row++) {
1543 printf ("[ %f", view_matrix[row][0]);
1544 for (column = 1; column < 4; column++) {
1545 printf (",\t%f", view_matrix[row][column]);
1547 printf ("\t]\n");
1549 printf ("\n");
1550 #endif
1552 ghid_invalidate_all ();
1556 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1557 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1558 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1559 #define LEAD_USER_ARC_COUNT 3
1560 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1561 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1562 #define LEAD_USER_COLOR_R 1.
1563 #define LEAD_USER_COLOR_G 1.
1564 #define LEAD_USER_COLOR_B 0.
1566 static void
1567 draw_lead_user (render_priv *priv)
1569 int i;
1570 double radius = priv->lead_user_radius;
1571 double width = MM_TO_COORD (LEAD_USER_WIDTH);
1572 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
1574 if (!priv->lead_user)
1575 return;
1577 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
1578 glEnable (GL_COLOR_LOGIC_OP);
1579 glLogicOp (GL_XOR);
1580 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
1583 /* arcs at the approrpriate radii */
1585 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
1587 if (radius < width)
1588 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1590 /* Draw an arc at radius */
1591 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
1592 radius, radius, 0, 360, gport->view.coord_per_px);
1595 hidgl_flush_triangles (&buffer);
1596 glPopAttrib ();
1599 gboolean
1600 lead_user_cb (gpointer data)
1602 render_priv *priv = data;
1603 Coord step;
1604 double elapsed_time;
1606 /* Queue a redraw */
1607 ghid_invalidate_all ();
1609 /* Update radius */
1610 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
1611 g_timer_start (priv->lead_user_timer);
1613 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
1614 if (priv->lead_user_radius > step)
1615 priv->lead_user_radius -= step;
1616 else
1617 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1619 return TRUE;
1622 void
1623 ghid_lead_user_to_location (Coord x, Coord y)
1625 render_priv *priv = gport->render_priv;
1627 ghid_cancel_lead_user ();
1629 priv->lead_user = true;
1630 priv->lead_user_x = x;
1631 priv->lead_user_y = y;
1632 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1633 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
1634 priv->lead_user_timer = g_timer_new ();
1637 void
1638 ghid_cancel_lead_user (void)
1640 render_priv *priv = gport->render_priv;
1642 if (priv->lead_user_timeout)
1643 g_source_remove (priv->lead_user_timeout);
1645 if (priv->lead_user_timer)
1646 g_timer_destroy (priv->lead_user_timer);
1648 if (priv->lead_user)
1649 ghid_invalidate_all ();
1651 priv->lead_user_timeout = 0;
1652 priv->lead_user_timer = NULL;
1653 priv->lead_user = false;