Pass an explicit graphics context to DrawAttached and DrawMark
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blobcfb647ee059d322b8975346da901c46878e6f177
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;
37 extern HID_DRAW ghid_graphics;
39 static hidGC current_gc = NULL;
41 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
43 #define USE_GC(gc) if (!use_gc(gc)) return
45 static enum mask_mode cur_mask = HID_MASK_OFF;
46 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
47 {0.0, 1.0, 0.0, 0.0},
48 {0.0, 0.0, 1.0, 0.0},
49 {0.0, 0.0, 0.0, 1.0}};
50 static GLfloat last_modelview_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 int global_view_2d = 1;
56 typedef struct render_priv {
57 GdkGLConfig *glconfig;
58 bool trans_lines;
59 bool in_context;
60 int subcomposite_stencil_bit;
61 char *current_colorname;
62 double current_alpha_mult;
63 GTimer *time_since_expose;
65 /* Feature for leading the user to a particular location */
66 guint lead_user_timeout;
67 GTimer *lead_user_timer;
68 bool lead_user;
69 Coord lead_user_radius;
70 Coord lead_user_x;
71 Coord lead_user_y;
73 hidGC crosshair_gc;
74 } render_priv;
77 typedef struct hid_gc_struct
79 HID *me_pointer;
81 const char *colorname;
82 double alpha_mult;
83 Coord width;
84 gint cap, join;
86 hid_gc_struct;
89 static void draw_lead_user (render_priv *priv);
90 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
93 static void
94 start_subcomposite (void)
96 render_priv *priv = gport->render_priv;
97 int stencil_bit;
99 /* Flush out any existing geoemtry to be rendered */
100 hidgl_flush_triangles (&buffer);
102 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
103 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
105 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
106 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
107 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
109 priv->subcomposite_stencil_bit = stencil_bit;
112 static void
113 end_subcomposite (void)
115 render_priv *priv = gport->render_priv;
117 /* Flush out any existing geoemtry to be rendered */
118 hidgl_flush_triangles (&buffer);
120 hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
122 glStencilMask (0);
123 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
124 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
126 priv->subcomposite_stencil_bit = 0;
131 ghid_set_layer (const char *name, int group, int empty)
133 render_priv *priv = gport->render_priv;
134 int idx = group;
135 if (idx >= 0 && idx < max_group)
137 int n = PCB->LayerGroups.Number[group];
138 for (idx = 0; idx < n-1; idx ++)
140 int ni = PCB->LayerGroups.Entries[group][idx];
141 if (ni >= 0 && ni < max_copper_layer + 2
142 && PCB->Data->Layer[ni].On)
143 break;
145 idx = PCB->LayerGroups.Entries[group][idx];
148 end_subcomposite ();
149 start_subcomposite ();
151 if (idx >= 0 && idx < max_copper_layer + 2)
153 priv->trans_lines = true;
154 return PCB->Data->Layer[idx].On;
156 if (idx < 0)
158 switch (SL_TYPE (idx))
160 case SL_INVISIBLE:
161 return PCB->InvisibleObjectsOn;
162 case SL_MASK:
163 if (SL_MYSIDE (idx))
164 return TEST_FLAG (SHOWMASKFLAG, PCB);
165 return 0;
166 case SL_SILK:
167 priv->trans_lines = true;
168 if (SL_MYSIDE (idx))
169 return PCB->ElementOn;
170 return 0;
171 case SL_ASSY:
172 return 0;
173 case SL_PDRILL:
174 case SL_UDRILL:
175 return 1;
176 case SL_RATS:
177 if (PCB->RatOn)
178 priv->trans_lines = true;
179 return PCB->RatOn;
182 return 0;
185 static void
186 ghid_end_layer (void)
188 end_subcomposite ();
191 void
192 ghid_destroy_gc (hidGC gc)
194 g_free (gc);
197 hidGC
198 ghid_make_gc (void)
200 hidGC rv;
202 rv = g_new0 (hid_gc_struct, 1);
203 rv->me_pointer = &ghid_hid;
204 rv->colorname = Settings.BackgroundColor;
205 rv->alpha_mult = 1.0;
206 return rv;
209 static void
210 ghid_draw_grid (BoxType *drawn_area)
212 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
213 return;
215 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
217 gport->grid_color.red ^= gport->bg_color.red;
218 gport->grid_color.green ^= gport->bg_color.green;
219 gport->grid_color.blue ^= gport->bg_color.blue;
222 glEnable (GL_COLOR_LOGIC_OP);
223 glLogicOp (GL_XOR);
225 glColor3f (gport->grid_color.red / 65535.,
226 gport->grid_color.green / 65535.,
227 gport->grid_color.blue / 65535.);
229 hidgl_draw_grid (drawn_area);
231 glDisable (GL_COLOR_LOGIC_OP);
234 static void
235 ghid_draw_bg_image (void)
237 static GLuint texture_handle = 0;
239 if (!ghidgui->bg_pixbuf)
240 return;
242 if (texture_handle == 0)
244 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
245 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
246 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
247 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
248 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
249 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
251 g_warn_if_fail (bits_per_sample == 8);
252 g_warn_if_fail (rowstride == width * n_channels);
254 glGenTextures (1, &texture_handle);
255 glBindTexture (GL_TEXTURE_2D, texture_handle);
257 /* XXX: We should proabbly determine what the maxmimum texture supported is,
258 * and if our image is larger, shrink it down using GDK pixbuf routines
259 * rather than having it fail below.
262 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
263 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
266 glBindTexture (GL_TEXTURE_2D, texture_handle);
268 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
269 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
270 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
271 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
272 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
273 glEnable (GL_TEXTURE_2D);
275 /* Render a quad with the background as a texture */
277 glBegin (GL_QUADS);
278 glTexCoord2d (0., 0.);
279 glVertex3i (0, 0, 0);
280 glTexCoord2d (1., 0.);
281 glVertex3i (PCB->MaxWidth, 0, 0);
282 glTexCoord2d (1., 1.);
283 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
284 glTexCoord2d (0., 1.);
285 glVertex3i (0, PCB->MaxHeight, 0);
286 glEnd ();
288 glDisable (GL_TEXTURE_2D);
291 void
292 ghid_use_mask (enum mask_mode mode)
294 static int stencil_bit = 0;
296 if (mode == cur_mask)
297 return;
299 /* Flush out any existing geoemtry to be rendered */
300 hidgl_flush_triangles (&buffer);
302 switch (mode)
304 case HID_MASK_BEFORE:
305 /* The HID asks not to receive this mask type, so warn if we get it */
306 g_return_if_reached ();
308 case HID_MASK_CLEAR:
309 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
310 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
311 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
312 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
313 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
314 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
315 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
316 break;
318 case HID_MASK_AFTER:
319 /* Drawing operations as masked to areas where the stencil buffer is '0' */
320 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
321 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
322 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
323 break;
325 case HID_MASK_OFF:
326 /* Disable stenciling */
327 hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */
328 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
329 break;
331 cur_mask = mode;
335 /* Config helper functions for when the user changes color preferences.
336 | set_special colors used in the gtkhid.
338 static void
339 set_special_grid_color (void)
341 if (!gport->colormap)
342 return;
343 gport->grid_color.red ^= gport->bg_color.red;
344 gport->grid_color.green ^= gport->bg_color.green;
345 gport->grid_color.blue ^= gport->bg_color.blue;
348 void
349 ghid_set_special_colors (HID_Attribute * ha)
351 if (!ha->name || !ha->value)
352 return;
353 if (!strcmp (ha->name, "background-color"))
355 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
356 set_special_grid_color ();
358 else if (!strcmp (ha->name, "off-limit-color"))
360 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
362 else if (!strcmp (ha->name, "grid-color"))
364 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
365 set_special_grid_color ();
369 typedef struct
371 int color_set;
372 GdkColor color;
373 double red;
374 double green;
375 double blue;
376 } ColorCache;
378 static void
379 set_gl_color_for_gc (hidGC gc)
381 render_priv *priv = gport->render_priv;
382 static void *cache = NULL;
383 hidval cval;
384 ColorCache *cc;
385 double r, g, b, a;
387 if (priv->current_colorname != NULL &&
388 strcmp (priv->current_colorname, gc->colorname) == 0 &&
389 priv->current_alpha_mult == gc->alpha_mult)
390 return;
392 free (priv->current_colorname);
393 priv->current_colorname = strdup (gc->colorname);
394 priv->current_alpha_mult = gc->alpha_mult;
396 if (gport->colormap == NULL)
397 gport->colormap = gtk_widget_get_colormap (gport->top_window);
398 if (strcmp (gc->colorname, "erase") == 0)
400 r = gport->bg_color.red / 65535.;
401 g = gport->bg_color.green / 65535.;
402 b = gport->bg_color.blue / 65535.;
403 a = 1.0;
405 else if (strcmp (gc->colorname, "drill") == 0)
407 r = gport->offlimits_color.red / 65535.;
408 g = gport->offlimits_color.green / 65535.;
409 b = gport->offlimits_color.blue / 65535.;
410 a = 0.85;
412 else
414 if (hid_cache_color (0, gc->colorname, &cval, &cache))
415 cc = (ColorCache *) cval.ptr;
416 else
418 cc = (ColorCache *) malloc (sizeof (ColorCache));
419 memset (cc, 0, sizeof (*cc));
420 cval.ptr = cc;
421 hid_cache_color (1, gc->colorname, &cval, &cache);
424 if (!cc->color_set)
426 if (gdk_color_parse (gc->colorname, &cc->color))
427 gdk_color_alloc (gport->colormap, &cc->color);
428 else
429 gdk_color_white (gport->colormap, &cc->color);
430 cc->red = cc->color.red / 65535.;
431 cc->green = cc->color.green / 65535.;
432 cc->blue = cc->color.blue / 65535.;
433 cc->color_set = 1;
435 r = cc->red;
436 g = cc->green;
437 b = cc->blue;
438 a = 0.7;
440 if (1) {
441 double maxi, mult;
442 a *= gc->alpha_mult;
443 if (!priv->trans_lines)
444 a = 1.0;
445 maxi = r;
446 if (g > maxi) maxi = g;
447 if (b > maxi) maxi = b;
448 mult = MIN (1 / a, 1 / maxi);
449 #if 1
450 r = r * mult;
451 g = g * mult;
452 b = b * mult;
453 #endif
456 if(!priv->in_context)
457 return;
459 hidgl_flush_triangles (&buffer);
460 glColor4d (r, g, b, a);
463 void
464 ghid_set_color (hidGC gc, const char *name)
466 gc->colorname = name;
467 set_gl_color_for_gc (gc);
470 void
471 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
473 gc->alpha_mult = alpha_mult;
474 set_gl_color_for_gc (gc);
477 void
478 ghid_set_line_cap (hidGC gc, EndCapStyle style)
480 gc->cap = style;
483 void
484 ghid_set_line_width (hidGC gc, Coord width)
486 gc->width = width;
490 void
491 ghid_set_draw_xor (hidGC gc, int xor)
493 /* NOT IMPLEMENTED */
495 /* Only presently called when setting up a crosshair GC.
496 * We manage our own drawing model for that anyway. */
499 void
500 ghid_set_draw_faded (hidGC gc, int faded)
502 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
505 void
506 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
508 printf ("ghid_set_line_cap_angle() -- not implemented\n");
511 static void
512 ghid_invalidate_current_gc (void)
514 current_gc = NULL;
517 static int
518 use_gc (hidGC gc)
520 if (gc->me_pointer != &ghid_hid)
522 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
523 abort ();
526 if (current_gc == gc)
527 return 1;
529 current_gc = gc;
531 set_gl_color_for_gc (gc);
532 return 1;
535 void
536 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
538 USE_GC (gc);
540 hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
543 void
544 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
545 Angle start_angle, Angle delta_angle)
547 USE_GC (gc);
549 hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
550 start_angle, delta_angle, gport->view.coord_per_px);
553 void
554 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
556 USE_GC (gc);
558 hidgl_draw_rect (x1, y1, x2, y2);
562 void
563 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
565 USE_GC (gc);
567 hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px);
571 void
572 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
574 USE_GC (gc);
576 hidgl_fill_polygon (n_coords, x, y);
579 void
580 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
582 USE_GC (gc);
584 hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px);
587 void
588 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
590 common_thindraw_pcb_polygon (gc, poly, clip_box);
591 ghid_set_alpha_mult (gc, 0.25);
592 gui->graphics->fill_pcb_polygon (gc, poly, clip_box);
593 ghid_set_alpha_mult (gc, 1.0);
596 void
597 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
599 USE_GC (gc);
601 hidgl_fill_rect (x1, y1, x2, y2);
604 void
605 ghid_invalidate_lr (int left, int right, int top, int bottom)
607 ghid_invalidate_all ();
610 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
611 void
612 ghid_invalidate_all ()
614 render_priv *priv = gport->render_priv;
615 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
617 ghid_draw_area_update (gport, NULL);
619 if (elapsed > MAX_ELAPSED)
620 gdk_window_process_all_updates ();
623 void
624 ghid_notify_crosshair_change (bool changes_complete)
626 /* We sometimes get called before the GUI is up */
627 if (gport->drawing_area == NULL)
628 return;
630 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
631 ghid_invalidate_all ();
634 void
635 ghid_notify_mark_change (bool changes_complete)
637 /* We sometimes get called before the GUI is up */
638 if (gport->drawing_area == NULL)
639 return;
641 /* FIXME: We could just invalidate the bounds of the mark? */
642 ghid_invalidate_all ();
645 static void
646 draw_right_cross (gint x, gint y, gint z)
648 glVertex3i (x, 0, z);
649 glVertex3i (x, PCB->MaxHeight, z);
650 glVertex3i (0, y, z);
651 glVertex3i (PCB->MaxWidth, y, z);
654 static void
655 draw_slanted_cross (gint x, gint y, gint z)
657 gint x0, y0, x1, y1;
659 x0 = x + (PCB->MaxHeight - y);
660 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
661 x1 = x - y;
662 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
663 y0 = y + (PCB->MaxWidth - x);
664 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
665 y1 = y - x;
666 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
667 glVertex3i (x0, y0, z);
668 glVertex3i (x1, y1, z);
670 x0 = x - (PCB->MaxHeight - y);
671 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
672 x1 = x + y;
673 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
674 y0 = y + x;
675 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
676 y1 = y - (PCB->MaxWidth - x);
677 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
678 glVertex3i (x0, y0, z);
679 glVertex3i (x1, y1, z);
682 static void
683 draw_dozen_cross (gint x, gint y, gint z)
685 gint x0, y0, x1, y1;
686 gdouble tan60 = sqrt (3);
688 x0 = x + (PCB->MaxHeight - y) / tan60;
689 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
690 x1 = x - y / tan60;
691 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
692 y0 = y + (PCB->MaxWidth - x) * tan60;
693 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
694 y1 = y - x * tan60;
695 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
696 glVertex3i (x0, y0, z);
697 glVertex3i (x1, y1, z);
699 x0 = x + (PCB->MaxHeight - y) * tan60;
700 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
701 x1 = x - y * tan60;
702 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
703 y0 = y + (PCB->MaxWidth - x) / tan60;
704 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
705 y1 = y - x / tan60;
706 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
707 glVertex3i (x0, y0, z);
708 glVertex3i (x1, y1, z);
710 x0 = x - (PCB->MaxHeight - y) / tan60;
711 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
712 x1 = x + y / tan60;
713 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
714 y0 = y + x * tan60;
715 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
716 y1 = y - (PCB->MaxWidth - x) * tan60;
717 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
718 glVertex3i (x0, y0, z);
719 glVertex3i (x1, y1, z);
721 x0 = x - (PCB->MaxHeight - y) * tan60;
722 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
723 x1 = x + y * tan60;
724 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
725 y0 = y + x / tan60;
726 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
727 y1 = y - (PCB->MaxWidth - x) / tan60;
728 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
729 glVertex3i (x0, y0, z);
730 glVertex3i (x1, y1, z);
733 static void
734 draw_crosshair (render_priv *priv)
736 gint x, y, z;
737 static int done_once = 0;
738 static GdkColor cross_color;
740 if (!done_once)
742 done_once = 1;
743 /* FIXME: when CrossColor changed from config */
744 ghid_map_color_string (Settings.CrossColor, &cross_color);
747 x = gport->crosshair_x;
748 y = gport->crosshair_y;
749 z = 0;
751 glEnable (GL_COLOR_LOGIC_OP);
752 glLogicOp (GL_XOR);
754 glColor3f (cross_color.red / 65535.,
755 cross_color.green / 65535.,
756 cross_color.blue / 65535.);
758 glBegin (GL_LINES);
760 draw_right_cross (x, y, z);
761 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
762 draw_slanted_cross (x, y, z);
763 if (Crosshair.shape == Dozen_Crosshair_Shape)
764 draw_dozen_cross (x, y, z);
766 glEnd ();
768 glDisable (GL_COLOR_LOGIC_OP);
771 void
772 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
774 render_priv *priv;
776 port->render_priv = priv = g_new0 (render_priv, 1);
777 port->render_priv->crosshair_gc = gui->graphics->make_gc ();
779 priv->time_since_expose = g_timer_new ();
781 gtk_gl_init(argc, argv);
783 /* setup GL-context */
784 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
785 GDK_GL_MODE_STENCIL |
786 GDK_GL_MODE_DOUBLE);
787 if (!priv->glconfig)
789 printf ("Could not setup GL-context!\n");
790 return; /* Should we abort? */
793 /* Setup HID function pointers specific to the GL renderer*/
794 ghid_hid.end_layer = ghid_end_layer;
795 ghid_graphics.fill_pcb_polygon = ghid_fill_pcb_polygon;
796 ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
799 void
800 ghid_shutdown_renderer (GHidPort *port)
802 render_priv *priv = port->render_priv;
804 gui->graphics->destroy_gc (priv->crosshair_gc);
805 ghid_cancel_lead_user ();
806 g_free (port->render_priv);
807 port->render_priv = NULL;
810 void
811 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
813 render_priv *priv = port->render_priv;
815 gtk_widget_set_gl_capability (widget,
816 priv->glconfig,
817 NULL,
818 TRUE,
819 GDK_GL_RGBA_TYPE);
822 void
823 ghid_drawing_area_configure_hook (GHidPort *port)
827 gboolean
828 ghid_start_drawing (GHidPort *port, GtkWidget *widget)
830 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
831 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
833 /* make GL-context "current" */
834 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
835 return FALSE;
837 port->render_priv->in_context = true;
839 return TRUE;
842 void
843 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
845 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
847 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
848 gdk_gl_drawable_swap_buffers (pGlDrawable);
849 else
850 glFlush ();
852 port->render_priv->in_context = false;
854 /* end drawing to current GL-context */
855 gdk_gl_drawable_gl_end (pGlDrawable);
858 void
859 ghid_screen_update (void)
863 #define Z_NEAR 3.0
864 gboolean
865 ghid_drawing_area_expose_cb (GtkWidget *widget,
866 GdkEventExpose *ev,
867 GHidPort *port)
869 render_priv *priv = port->render_priv;
870 GtkAllocation allocation;
871 BoxType region;
872 Coord min_x, min_y;
873 Coord max_x, max_y;
874 Coord new_x, new_y;
875 Coord min_depth;
876 Coord max_depth;
878 gtk_widget_get_allocation (widget, &allocation);
880 ghid_start_drawing (port, widget);
881 hidgl_start_render ();
883 /* If we don't have any stencil bits available,
884 we can't use the hidgl polygon drawing routine */
885 /* TODO: We could use the GLU tessellator though */
886 if (hidgl_stencil_bits() == 0)
887 ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon;
889 glEnable (GL_BLEND);
890 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
892 glViewport (0, 0, allocation.width, allocation.height);
894 glEnable (GL_SCISSOR_TEST);
895 glScissor (ev->area.x,
896 allocation.height - ev->area.height - ev->area.y,
897 ev->area.width, ev->area.height);
899 glMatrixMode (GL_PROJECTION);
900 glLoadIdentity ();
901 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
902 glMatrixMode (GL_MODELVIEW);
903 glLoadIdentity ();
904 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
905 glMultMatrixf ((GLfloat *)view_matrix);
906 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
907 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
908 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
909 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
910 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
911 -port->view.x0,
912 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
913 -port->view.y0, 0);
914 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
916 glEnable (GL_STENCIL_TEST);
917 glClearColor (port->offlimits_color.red / 65535.,
918 port->offlimits_color.green / 65535.,
919 port->offlimits_color.blue / 65535.,
920 1.);
921 glStencilMask (~0);
922 glClearStencil (0);
923 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
924 hidgl_reset_stencil_usage ();
926 /* Disable the stencil test until we need it - otherwise it gets dirty */
927 glDisable (GL_STENCIL_TEST);
928 glStencilMask (0);
929 glStencilFunc (GL_ALWAYS, 0, 0);
931 /* Test the 8 corners of a cube spanning the event */
932 min_depth = -50; /* FIXME */
933 max_depth = 0; /* FIXME */
935 ghid_unproject_to_z_plane (ev->area.x,
936 ev->area.y,
937 min_depth, &new_x, &new_y);
938 max_x = min_x = new_x;
939 max_y = min_y = new_y;
941 ghid_unproject_to_z_plane (ev->area.x,
942 ev->area.y,
943 max_depth, &new_x, &new_y);
944 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
945 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
947 /* */
948 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
949 ev->area.y,
950 min_depth, &new_x, &new_y);
951 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
952 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
954 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
955 max_depth, &new_x, &new_y);
956 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
957 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
959 /* */
960 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
961 ev->area.y + ev->area.height,
962 min_depth, &new_x, &new_y);
963 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
964 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
966 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
967 ev->area.y + ev->area.height,
968 max_depth, &new_x, &new_y);
969 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
970 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
972 /* */
973 ghid_unproject_to_z_plane (ev->area.x,
974 ev->area.y + ev->area.height,
975 min_depth,
976 &new_x, &new_y);
977 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
978 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
980 ghid_unproject_to_z_plane (ev->area.x,
981 ev->area.y + ev->area.height,
982 max_depth,
983 &new_x, &new_y);
984 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
985 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
987 region.X1 = min_x; region.X2 = max_x + 1;
988 region.Y1 = min_y; region.Y2 = max_y + 1;
990 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
991 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
992 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
993 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
995 glColor3f (port->bg_color.red / 65535.,
996 port->bg_color.green / 65535.,
997 port->bg_color.blue / 65535.);
999 glBegin (GL_QUADS);
1000 glVertex3i (0, 0, -50);
1001 glVertex3i (PCB->MaxWidth, 0, -50);
1002 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
1003 glVertex3i (0, PCB->MaxHeight, -50);
1004 glEnd ();
1006 ghid_draw_bg_image ();
1008 ghid_invalidate_current_gc ();
1009 hid_expose_callback (&ghid_hid, &region, 0);
1010 hidgl_flush_triangles (&buffer);
1012 ghid_draw_grid (&region);
1014 ghid_invalidate_current_gc ();
1016 DrawAttached (priv->crosshair_gc);
1017 DrawMark (priv->crosshair_gc);
1018 hidgl_flush_triangles (&buffer);
1020 draw_crosshair (priv);
1021 hidgl_flush_triangles (&buffer);
1023 draw_lead_user (priv);
1025 hidgl_finish_render ();
1026 ghid_end_drawing (port, widget);
1028 g_timer_start (priv->time_since_expose);
1030 return FALSE;
1033 /* This realize callback is used to work around a crash bug in some mesa
1034 * versions (observed on a machine running the intel i965 driver. It isn't
1035 * obvious why it helps, but somehow fiddling with the GL context here solves
1036 * the issue. The problem appears to have been fixed in recent mesa versions.
1038 void
1039 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1041 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1042 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1044 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1045 return;
1047 gdk_gl_drawable_gl_end (gldrawable);
1048 return;
1051 gboolean
1052 ghid_pinout_preview_expose (GtkWidget *widget,
1053 GdkEventExpose *ev)
1055 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
1056 GtkAllocation allocation;
1057 view_data save_view;
1058 int save_width, save_height;
1059 Coord save_max_width;
1060 Coord save_max_height;
1061 double xz, yz;
1063 save_view = gport->view;
1064 save_width = gport->width;
1065 save_height = gport->height;
1066 save_max_width = PCB->MaxWidth;
1067 save_max_height = PCB->MaxHeight;
1069 /* Setup zoom factor for drawing routines */
1071 gtk_widget_get_allocation (widget, &allocation);
1072 xz = (double) pinout->x_max / allocation.width;
1073 yz = (double) pinout->y_max / allocation.height;
1074 if (xz > yz)
1075 gport->view.coord_per_px = xz;
1076 else
1077 gport->view.coord_per_px = yz;
1079 gport->width = allocation.width;
1080 gport->height = allocation.height;
1081 gport->view.width = allocation.width * gport->view.coord_per_px;
1082 gport->view.height = allocation.height * gport->view.coord_per_px;
1083 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
1084 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
1085 PCB->MaxWidth = pinout->x_max;
1086 PCB->MaxHeight = pinout->y_max;
1088 ghid_start_drawing (gport, widget);
1089 hidgl_start_render ();
1091 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
1092 * call set_layer() as appropriate for us to sub-composite rendering
1093 * from each layer when drawing a single element. If we leave alpha-
1094 * blending on, it means text and overlapping pads are rendered ugly.
1097 glEnable (GL_BLEND);
1098 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1099 #endif
1101 glViewport (0, 0, allocation.width, allocation.height);
1103 #if 0 /* We disable the scissor test here, as it is interacting badly with
1104 * being handed expose events which don't cover the whole window.
1105 * As we have a double-buffered GL window, we end up with unintialised
1106 * contents remaining in the unpainted areas (outside the scissor
1107 * region), and these are being flipped onto the screen.
1109 * The debugging code below shows multiple expose events when the
1110 * window is shown the first time, some of which are very small.
1112 * XXX: There is clearly a perforamnce issue here, in that we may
1113 * be rendering the preview more times, and over a larger area
1114 * than is really required.
1117 glEnable (GL_SCISSOR_TEST);
1118 glScissor (ev->area.x,
1119 allocation.height - ev->area.height - ev->area.y,
1120 ev->area.width, ev->area.height);
1121 #endif
1123 #ifdef DEBUG
1124 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
1125 ev->area.x, ev->area.y, ev->area.width, ev->area.height,
1126 (double)ev->area.x,
1127 (double)(allocation.height - ev->area.height - ev->area.y),
1128 (double)ev->area.width,
1129 (double)ev->area.height);
1130 #endif
1132 glMatrixMode (GL_PROJECTION);
1133 glLoadIdentity ();
1134 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1135 glMatrixMode (GL_MODELVIEW);
1136 glLoadIdentity ();
1137 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1139 glClearColor (gport->bg_color.red / 65535.,
1140 gport->bg_color.green / 65535.,
1141 gport->bg_color.blue / 65535.,
1142 1.);
1143 glStencilMask (~0);
1144 glClearStencil (0);
1145 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1146 hidgl_reset_stencil_usage ();
1148 /* Disable the stencil test until we need it - otherwise it gets dirty */
1149 glDisable (GL_STENCIL_TEST);
1150 glStencilMask (0);
1151 glStencilFunc (GL_ALWAYS, 0, 0);
1153 /* call the drawing routine */
1154 ghid_invalidate_current_gc ();
1155 glPushMatrix ();
1156 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1157 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1158 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1159 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1160 -gport->view.x0,
1161 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1162 -gport->view.y0, 0);
1164 hid_expose_callback (&ghid_hid, NULL, pinout->element);
1165 hidgl_flush_triangles (&buffer);
1166 glPopMatrix ();
1168 hidgl_finish_render ();
1169 ghid_end_drawing (gport, widget);
1171 gport->view = save_view;
1172 gport->width = save_width;
1173 gport->height = save_height;
1174 PCB->MaxWidth = save_max_width;
1175 PCB->MaxHeight = save_max_height;
1177 return FALSE;
1181 GdkPixmap *
1182 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
1184 GdkGLConfig *glconfig;
1185 GdkPixmap *pixmap;
1186 GdkGLPixmap *glpixmap;
1187 GdkGLContext* glcontext;
1188 GdkGLDrawable* gldrawable;
1189 view_data save_view;
1190 int save_width, save_height;
1191 BoxType region;
1193 save_view = gport->view;
1194 save_width = gport->width;
1195 save_height = gport->height;
1197 /* Setup rendering context for drawing routines
1200 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
1201 GDK_GL_MODE_STENCIL |
1202 GDK_GL_MODE_SINGLE);
1204 pixmap = gdk_pixmap_new (NULL, width, height, depth);
1205 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
1206 gldrawable = GDK_GL_DRAWABLE (glpixmap);
1207 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
1209 /* Setup zoom factor for drawing routines */
1211 gport->view.coord_per_px = zoom;
1212 gport->width = width;
1213 gport->height = height;
1214 gport->view.width = width * gport->view.coord_per_px;
1215 gport->view.height = height * gport->view.coord_per_px;
1216 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
1217 gport->view.x0 -= gport->view.height / 2;
1218 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
1219 gport->view.y0 -= gport->view.width / 2;
1221 /* make GL-context "current" */
1222 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
1223 return NULL;
1225 hidgl_start_render ();
1226 gport->render_priv->in_context = true;
1228 glEnable (GL_BLEND);
1229 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1231 glViewport (0, 0, width, height);
1233 glEnable (GL_SCISSOR_TEST);
1234 glScissor (0, 0, width, height);
1236 glMatrixMode (GL_PROJECTION);
1237 glLoadIdentity ();
1238 glOrtho (0, width, height, 0, -100000, 100000);
1239 glMatrixMode (GL_MODELVIEW);
1240 glLoadIdentity ();
1241 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1243 glClearColor (gport->bg_color.red / 65535.,
1244 gport->bg_color.green / 65535.,
1245 gport->bg_color.blue / 65535.,
1246 1.);
1247 glStencilMask (~0);
1248 glClearStencil (0);
1249 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1250 hidgl_reset_stencil_usage ();
1252 /* Disable the stencil test until we need it - otherwise it gets dirty */
1253 glDisable (GL_STENCIL_TEST);
1254 glStencilMask (0);
1255 glStencilFunc (GL_ALWAYS, 0, 0);
1257 /* call the drawing routine */
1258 ghid_invalidate_current_gc ();
1259 glPushMatrix ();
1260 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1261 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1262 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1263 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1264 -gport->view.x0,
1265 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1266 -gport->view.y0, 0);
1268 region.X1 = MIN(Px(0), Px(gport->width + 1));
1269 region.Y1 = MIN(Py(0), Py(gport->height + 1));
1270 region.X2 = MAX(Px(0), Px(gport->width + 1));
1271 region.Y2 = MAX(Py(0), Py(gport->height + 1));
1273 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1274 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1275 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1276 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1278 hid_expose_callback (&ghid_hid, &region, NULL);
1279 hidgl_flush_triangles (&buffer);
1280 glPopMatrix ();
1282 glFlush ();
1284 hidgl_finish_render ();
1286 /* end drawing to current GL-context */
1287 gport->render_priv->in_context = false;
1288 gdk_gl_drawable_gl_end (gldrawable);
1290 gdk_pixmap_unset_gl_capability (pixmap);
1292 g_object_unref (glconfig);
1293 g_object_unref (glcontext);
1295 gport->view = save_view;
1296 gport->width = save_width;
1297 gport->height = save_height;
1299 return pixmap;
1302 HID_DRAW *
1303 ghid_request_debug_draw (void)
1305 GHidPort *port = gport;
1306 GtkWidget *widget = port->drawing_area;
1307 GtkAllocation allocation;
1309 gtk_widget_get_allocation (widget, &allocation);
1311 ghid_start_drawing (port, widget);
1312 hidgl_start_render ();
1314 glViewport (0, 0, allocation.width, allocation.height);
1316 glMatrixMode (GL_PROJECTION);
1317 glLoadIdentity ();
1318 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
1319 glMatrixMode (GL_MODELVIEW);
1320 glLoadIdentity ();
1321 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1323 ghid_invalidate_current_gc ();
1325 /* Setup stenciling */
1326 glDisable (GL_STENCIL_TEST);
1328 glPushMatrix ();
1329 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1330 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1331 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1332 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1333 -port->view.x0,
1334 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1335 -port->view.y0, 0);
1337 return ghid_hid.graphics;
1340 void
1341 ghid_flush_debug_draw (void)
1343 GtkWidget *widget = gport->drawing_area;
1344 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1346 hidgl_flush_triangles (&buffer);
1348 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1349 gdk_gl_drawable_swap_buffers (pGlDrawable);
1350 else
1351 glFlush ();
1354 void
1355 ghid_finish_debug_draw (void)
1357 hidgl_flush_triangles (&buffer);
1358 glPopMatrix ();
1360 hidgl_finish_render ();
1361 ghid_end_drawing (gport, gport->drawing_area);
1364 static float
1365 determinant_2x2 (float m[2][2])
1367 float det;
1368 det = m[0][0] * m[1][1] -
1369 m[0][1] * m[1][0];
1370 return det;
1373 #if 0
1374 static float
1375 determinant_4x4 (float m[4][4])
1377 float det;
1378 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] -
1379 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
1380 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
1381 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
1382 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
1383 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
1384 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
1385 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
1386 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
1387 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
1388 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
1389 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
1390 return det;
1392 #endif
1394 static void
1395 invert_2x2 (float m[2][2], float out[2][2])
1397 float scale = 1 / determinant_2x2 (m);
1398 out[0][0] = m[1][1] * scale;
1399 out[0][1] = -m[0][1] * scale;
1400 out[1][0] = -m[1][0] * scale;
1401 out[1][1] = m[0][0] * scale;
1404 #if 0
1405 static void
1406 invert_4x4 (float m[4][4], float out[4][4])
1408 float scale = 1 / determinant_4x4 (m);
1410 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
1411 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
1412 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
1413 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
1414 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
1415 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
1416 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
1417 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
1418 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
1419 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
1420 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
1421 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
1422 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
1423 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
1424 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
1425 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
1426 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
1427 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
1428 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
1429 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
1430 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
1431 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
1432 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
1433 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
1434 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
1435 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
1436 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
1437 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
1438 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
1439 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
1440 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
1441 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
1442 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
1443 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
1444 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
1445 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
1446 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
1447 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
1448 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
1449 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
1450 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
1451 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
1452 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
1453 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
1454 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
1455 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
1456 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
1457 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
1459 #endif
1462 static void
1463 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
1465 float mat[2][2];
1466 float inv_mat[2][2];
1467 float x, y;
1470 ex = view_matrix[0][0] * vx +
1471 view_matrix[0][1] * vy +
1472 view_matrix[0][2] * vz +
1473 view_matrix[0][3] * 1;
1474 ey = view_matrix[1][0] * vx +
1475 view_matrix[1][1] * vy +
1476 view_matrix[1][2] * vz +
1477 view_matrix[1][3] * 1;
1478 UNKNOWN ez = view_matrix[2][0] * vx +
1479 view_matrix[2][1] * vy +
1480 view_matrix[2][2] * vz +
1481 view_matrix[2][3] * 1;
1483 ex - view_matrix[0][3] * 1
1484 - view_matrix[0][2] * vz
1485 = view_matrix[0][0] * vx +
1486 view_matrix[0][1] * vy;
1488 ey - view_matrix[1][3] * 1
1489 - view_matrix[1][2] * vz
1490 = view_matrix[1][0] * vx +
1491 view_matrix[1][1] * vy;
1494 /* NB: last_modelview_matrix is transposed in memory! */
1495 x = (float)ex - last_modelview_matrix[3][0] * 1
1496 - last_modelview_matrix[2][0] * pcb_z;
1498 y = (float)ey - last_modelview_matrix[3][1] * 1
1499 - last_modelview_matrix[2][1] * pcb_z;
1502 x = view_matrix[0][0] * vx +
1503 view_matrix[0][1] * vy;
1505 y = view_matrix[1][0] * vx +
1506 view_matrix[1][1] * vy;
1508 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1509 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1512 mat[0][0] = last_modelview_matrix[0][0];
1513 mat[0][1] = last_modelview_matrix[1][0];
1514 mat[1][0] = last_modelview_matrix[0][1];
1515 mat[1][1] = last_modelview_matrix[1][1];
1517 /* if (determinant_2x2 (mat) < 0.00001) */
1518 /* printf ("Determinant is quite small\n"); */
1520 invert_2x2 (mat, inv_mat);
1522 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
1523 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
1527 bool
1528 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
1530 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
1532 return true;
1535 bool
1536 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
1538 /* NB: last_modelview_matrix is transposed in memory */
1539 float w = last_modelview_matrix[0][3] * (float)pcb_x +
1540 last_modelview_matrix[1][3] * (float)pcb_y +
1541 last_modelview_matrix[2][3] * 0. +
1542 last_modelview_matrix[3][3] * 1.;
1544 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
1545 last_modelview_matrix[1][0] * (float)pcb_y +
1546 last_modelview_matrix[2][0] * 0. +
1547 last_modelview_matrix[3][0] * 1.) / w;
1548 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
1549 last_modelview_matrix[1][1] * (float)pcb_y +
1550 last_modelview_matrix[2][1] * 0. +
1551 last_modelview_matrix[3][1] * 1.) / w;
1553 return true;
1556 void
1557 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
1559 global_view_2d = view_2d;
1560 ghid_invalidate_all ();
1563 void
1564 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
1566 #ifdef DEBUG_ROTATE
1567 int row, column;
1568 #endif
1570 build_rotmatrix (view_matrix, quarternion);
1572 #ifdef DEBUG_ROTATE
1573 for (row = 0; row < 4; row++) {
1574 printf ("[ %f", view_matrix[row][0]);
1575 for (column = 1; column < 4; column++) {
1576 printf (",\t%f", view_matrix[row][column]);
1578 printf ("\t]\n");
1580 printf ("\n");
1581 #endif
1583 ghid_invalidate_all ();
1587 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1588 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1589 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1590 #define LEAD_USER_ARC_COUNT 3
1591 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1592 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1593 #define LEAD_USER_COLOR_R 1.
1594 #define LEAD_USER_COLOR_G 1.
1595 #define LEAD_USER_COLOR_B 0.
1597 static void
1598 draw_lead_user (render_priv *priv)
1600 int i;
1601 double radius = priv->lead_user_radius;
1602 double width = MM_TO_COORD (LEAD_USER_WIDTH);
1603 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
1605 if (!priv->lead_user)
1606 return;
1608 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
1609 glEnable (GL_COLOR_LOGIC_OP);
1610 glLogicOp (GL_XOR);
1611 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
1614 /* arcs at the approrpriate radii */
1616 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
1618 if (radius < width)
1619 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1621 /* Draw an arc at radius */
1622 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
1623 radius, radius, 0, 360, gport->view.coord_per_px);
1626 hidgl_flush_triangles (&buffer);
1627 glPopAttrib ();
1630 gboolean
1631 lead_user_cb (gpointer data)
1633 render_priv *priv = data;
1634 Coord step;
1635 double elapsed_time;
1637 /* Queue a redraw */
1638 ghid_invalidate_all ();
1640 /* Update radius */
1641 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
1642 g_timer_start (priv->lead_user_timer);
1644 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
1645 if (priv->lead_user_radius > step)
1646 priv->lead_user_radius -= step;
1647 else
1648 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1650 return TRUE;
1653 void
1654 ghid_lead_user_to_location (Coord x, Coord y)
1656 render_priv *priv = gport->render_priv;
1658 ghid_cancel_lead_user ();
1660 priv->lead_user = true;
1661 priv->lead_user_x = x;
1662 priv->lead_user_y = y;
1663 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1664 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
1665 priv->lead_user_timer = g_timer_new ();
1668 void
1669 ghid_cancel_lead_user (void)
1671 render_priv *priv = gport->render_priv;
1673 if (priv->lead_user_timeout)
1674 g_source_remove (priv->lead_user_timeout);
1676 if (priv->lead_user_timer)
1677 g_timer_destroy (priv->lead_user_timer);
1679 if (priv->lead_user)
1680 ghid_invalidate_all ();
1682 priv->lead_user_timeout = 0;
1683 priv->lead_user_timer = NULL;
1684 priv->lead_user = false;