Rename HID_DRAW_API to just HID_DRAW
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blob43172c1f7c39a46af7710bb7b88818276d9b889c
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 } render_priv;
76 typedef struct hid_gc_struct
78 HID *me_pointer;
80 const char *colorname;
81 double alpha_mult;
82 Coord width;
83 gint cap, join;
85 hid_gc_struct;
88 static void draw_lead_user (render_priv *priv);
89 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
92 static void
93 start_subcomposite (void)
95 render_priv *priv = gport->render_priv;
96 int stencil_bit;
98 /* Flush out any existing geoemtry to be rendered */
99 hidgl_flush_triangles (&buffer);
101 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
102 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
104 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
105 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
106 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
108 priv->subcomposite_stencil_bit = stencil_bit;
111 static void
112 end_subcomposite (void)
114 render_priv *priv = gport->render_priv;
116 /* Flush out any existing geoemtry to be rendered */
117 hidgl_flush_triangles (&buffer);
119 hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
121 glStencilMask (0);
122 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
123 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
125 priv->subcomposite_stencil_bit = 0;
130 ghid_set_layer (const char *name, int group, int empty)
132 render_priv *priv = gport->render_priv;
133 int idx = group;
134 if (idx >= 0 && idx < max_group)
136 int n = PCB->LayerGroups.Number[group];
137 for (idx = 0; idx < n-1; idx ++)
139 int ni = PCB->LayerGroups.Entries[group][idx];
140 if (ni >= 0 && ni < max_copper_layer + 2
141 && PCB->Data->Layer[ni].On)
142 break;
144 idx = PCB->LayerGroups.Entries[group][idx];
147 end_subcomposite ();
148 start_subcomposite ();
150 if (idx >= 0 && idx < max_copper_layer + 2)
152 priv->trans_lines = true;
153 return PCB->Data->Layer[idx].On;
155 if (idx < 0)
157 switch (SL_TYPE (idx))
159 case SL_INVISIBLE:
160 return PCB->InvisibleObjectsOn;
161 case SL_MASK:
162 if (SL_MYSIDE (idx))
163 return TEST_FLAG (SHOWMASKFLAG, PCB);
164 return 0;
165 case SL_SILK:
166 priv->trans_lines = true;
167 if (SL_MYSIDE (idx))
168 return PCB->ElementOn;
169 return 0;
170 case SL_ASSY:
171 return 0;
172 case SL_PDRILL:
173 case SL_UDRILL:
174 return 1;
175 case SL_RATS:
176 if (PCB->RatOn)
177 priv->trans_lines = true;
178 return PCB->RatOn;
181 return 0;
184 static void
185 ghid_end_layer (void)
187 end_subcomposite ();
190 void
191 ghid_destroy_gc (hidGC gc)
193 g_free (gc);
196 hidGC
197 ghid_make_gc (void)
199 hidGC rv;
201 rv = g_new0 (hid_gc_struct, 1);
202 rv->me_pointer = &ghid_hid;
203 rv->colorname = Settings.BackgroundColor;
204 rv->alpha_mult = 1.0;
205 return rv;
208 static void
209 ghid_draw_grid (BoxType *drawn_area)
211 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
212 return;
214 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
216 gport->grid_color.red ^= gport->bg_color.red;
217 gport->grid_color.green ^= gport->bg_color.green;
218 gport->grid_color.blue ^= gport->bg_color.blue;
221 glEnable (GL_COLOR_LOGIC_OP);
222 glLogicOp (GL_XOR);
224 glColor3f (gport->grid_color.red / 65535.,
225 gport->grid_color.green / 65535.,
226 gport->grid_color.blue / 65535.);
228 hidgl_draw_grid (drawn_area);
230 glDisable (GL_COLOR_LOGIC_OP);
233 static void
234 ghid_draw_bg_image (void)
236 static GLuint texture_handle = 0;
238 if (!ghidgui->bg_pixbuf)
239 return;
241 if (texture_handle == 0)
243 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
244 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
245 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
246 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
247 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
248 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
250 g_warn_if_fail (bits_per_sample == 8);
251 g_warn_if_fail (rowstride == width * n_channels);
253 glGenTextures (1, &texture_handle);
254 glBindTexture (GL_TEXTURE_2D, texture_handle);
256 /* XXX: We should proabbly determine what the maxmimum texture supported is,
257 * and if our image is larger, shrink it down using GDK pixbuf routines
258 * rather than having it fail below.
261 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
262 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
265 glBindTexture (GL_TEXTURE_2D, texture_handle);
267 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
268 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
269 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
270 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
271 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
272 glEnable (GL_TEXTURE_2D);
274 /* Render a quad with the background as a texture */
276 glBegin (GL_QUADS);
277 glTexCoord2d (0., 0.);
278 glVertex3i (0, 0, 0);
279 glTexCoord2d (1., 0.);
280 glVertex3i (PCB->MaxWidth, 0, 0);
281 glTexCoord2d (1., 1.);
282 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
283 glTexCoord2d (0., 1.);
284 glVertex3i (0, PCB->MaxHeight, 0);
285 glEnd ();
287 glDisable (GL_TEXTURE_2D);
290 void
291 ghid_use_mask (enum mask_mode mode)
293 static int stencil_bit = 0;
295 if (mode == cur_mask)
296 return;
298 /* Flush out any existing geoemtry to be rendered */
299 hidgl_flush_triangles (&buffer);
301 switch (mode)
303 case HID_MASK_BEFORE:
304 /* The HID asks not to receive this mask type, so warn if we get it */
305 g_return_if_reached ();
307 case HID_MASK_CLEAR:
308 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
309 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
310 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
311 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
312 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
313 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
314 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
315 break;
317 case HID_MASK_AFTER:
318 /* Drawing operations as masked to areas where the stencil buffer is '0' */
319 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
320 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
321 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
322 break;
324 case HID_MASK_OFF:
325 /* Disable stenciling */
326 hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */
327 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
328 break;
330 cur_mask = mode;
334 /* Config helper functions for when the user changes color preferences.
335 | set_special colors used in the gtkhid.
337 static void
338 set_special_grid_color (void)
340 if (!gport->colormap)
341 return;
342 gport->grid_color.red ^= gport->bg_color.red;
343 gport->grid_color.green ^= gport->bg_color.green;
344 gport->grid_color.blue ^= gport->bg_color.blue;
347 void
348 ghid_set_special_colors (HID_Attribute * ha)
350 if (!ha->name || !ha->value)
351 return;
352 if (!strcmp (ha->name, "background-color"))
354 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
355 set_special_grid_color ();
357 else if (!strcmp (ha->name, "off-limit-color"))
359 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
361 else if (!strcmp (ha->name, "grid-color"))
363 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
364 set_special_grid_color ();
368 typedef struct
370 int color_set;
371 GdkColor color;
372 double red;
373 double green;
374 double blue;
375 } ColorCache;
377 static void
378 set_gl_color_for_gc (hidGC gc)
380 render_priv *priv = gport->render_priv;
381 static void *cache = NULL;
382 hidval cval;
383 ColorCache *cc;
384 double r, g, b, a;
386 if (priv->current_colorname != NULL &&
387 strcmp (priv->current_colorname, gc->colorname) == 0 &&
388 priv->current_alpha_mult == gc->alpha_mult)
389 return;
391 free (priv->current_colorname);
392 priv->current_colorname = strdup (gc->colorname);
393 priv->current_alpha_mult = gc->alpha_mult;
395 if (gport->colormap == NULL)
396 gport->colormap = gtk_widget_get_colormap (gport->top_window);
397 if (strcmp (gc->colorname, "erase") == 0)
399 r = gport->bg_color.red / 65535.;
400 g = gport->bg_color.green / 65535.;
401 b = gport->bg_color.blue / 65535.;
402 a = 1.0;
404 else if (strcmp (gc->colorname, "drill") == 0)
406 r = gport->offlimits_color.red / 65535.;
407 g = gport->offlimits_color.green / 65535.;
408 b = gport->offlimits_color.blue / 65535.;
409 a = 0.85;
411 else
413 if (hid_cache_color (0, gc->colorname, &cval, &cache))
414 cc = (ColorCache *) cval.ptr;
415 else
417 cc = (ColorCache *) malloc (sizeof (ColorCache));
418 memset (cc, 0, sizeof (*cc));
419 cval.ptr = cc;
420 hid_cache_color (1, gc->colorname, &cval, &cache);
423 if (!cc->color_set)
425 if (gdk_color_parse (gc->colorname, &cc->color))
426 gdk_color_alloc (gport->colormap, &cc->color);
427 else
428 gdk_color_white (gport->colormap, &cc->color);
429 cc->red = cc->color.red / 65535.;
430 cc->green = cc->color.green / 65535.;
431 cc->blue = cc->color.blue / 65535.;
432 cc->color_set = 1;
434 r = cc->red;
435 g = cc->green;
436 b = cc->blue;
437 a = 0.7;
439 if (1) {
440 double maxi, mult;
441 a *= gc->alpha_mult;
442 if (!priv->trans_lines)
443 a = 1.0;
444 maxi = r;
445 if (g > maxi) maxi = g;
446 if (b > maxi) maxi = b;
447 mult = MIN (1 / a, 1 / maxi);
448 #if 1
449 r = r * mult;
450 g = g * mult;
451 b = b * mult;
452 #endif
455 if(!priv->in_context)
456 return;
458 hidgl_flush_triangles (&buffer);
459 glColor4d (r, g, b, a);
462 void
463 ghid_set_color (hidGC gc, const char *name)
465 gc->colorname = name;
466 set_gl_color_for_gc (gc);
469 void
470 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
472 gc->alpha_mult = alpha_mult;
473 set_gl_color_for_gc (gc);
476 void
477 ghid_set_line_cap (hidGC gc, EndCapStyle style)
479 gc->cap = style;
482 void
483 ghid_set_line_width (hidGC gc, Coord width)
485 gc->width = width;
489 void
490 ghid_set_draw_xor (hidGC gc, int xor)
492 /* NOT IMPLEMENTED */
494 /* Only presently called when setting up a crosshair GC.
495 * We manage our own drawing model for that anyway. */
498 void
499 ghid_set_draw_faded (hidGC gc, int faded)
501 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
504 void
505 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
507 printf ("ghid_set_line_cap_angle() -- not implemented\n");
510 static void
511 ghid_invalidate_current_gc (void)
513 current_gc = NULL;
516 static int
517 use_gc (hidGC gc)
519 if (gc->me_pointer != &ghid_hid)
521 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
522 abort ();
525 if (current_gc == gc)
526 return 1;
528 current_gc = gc;
530 set_gl_color_for_gc (gc);
531 return 1;
534 void
535 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
537 USE_GC (gc);
539 hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
542 void
543 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
544 Angle start_angle, Angle delta_angle)
546 USE_GC (gc);
548 hidgl_draw_arc (gc->width, cx, cy, xradius, yradius,
549 start_angle, delta_angle, gport->view.coord_per_px);
552 void
553 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
555 USE_GC (gc);
557 hidgl_draw_rect (x1, y1, x2, y2);
561 void
562 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
564 USE_GC (gc);
566 hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px);
570 void
571 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
573 USE_GC (gc);
575 hidgl_fill_polygon (n_coords, x, y);
578 void
579 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
581 USE_GC (gc);
583 hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px);
586 void
587 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
589 common_thindraw_pcb_polygon (gc, poly, clip_box);
590 ghid_set_alpha_mult (gc, 0.25);
591 ghid_fill_pcb_polygon (gc, poly, clip_box);
592 ghid_set_alpha_mult (gc, 1.0);
595 void
596 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
598 USE_GC (gc);
600 hidgl_fill_rect (x1, y1, x2, y2);
603 void
604 ghid_invalidate_lr (int left, int right, int top, int bottom)
606 ghid_invalidate_all ();
609 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
610 void
611 ghid_invalidate_all ()
613 render_priv *priv = gport->render_priv;
614 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
616 ghid_draw_area_update (gport, NULL);
618 if (elapsed > MAX_ELAPSED)
619 gdk_window_process_all_updates ();
622 void
623 ghid_notify_crosshair_change (bool changes_complete)
625 /* We sometimes get called before the GUI is up */
626 if (gport->drawing_area == NULL)
627 return;
629 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
630 ghid_invalidate_all ();
633 void
634 ghid_notify_mark_change (bool changes_complete)
636 /* We sometimes get called before the GUI is up */
637 if (gport->drawing_area == NULL)
638 return;
640 /* FIXME: We could just invalidate the bounds of the mark? */
641 ghid_invalidate_all ();
644 static void
645 draw_right_cross (gint x, gint y, gint z)
647 glVertex3i (x, 0, z);
648 glVertex3i (x, PCB->MaxHeight, z);
649 glVertex3i (0, y, z);
650 glVertex3i (PCB->MaxWidth, y, z);
653 static void
654 draw_slanted_cross (gint x, gint y, gint z)
656 gint x0, y0, x1, y1;
658 x0 = x + (PCB->MaxHeight - y);
659 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
660 x1 = x - y;
661 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
662 y0 = y + (PCB->MaxWidth - x);
663 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
664 y1 = y - x;
665 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
666 glVertex3i (x0, y0, z);
667 glVertex3i (x1, y1, z);
669 x0 = x - (PCB->MaxHeight - y);
670 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
671 x1 = x + y;
672 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
673 y0 = y + x;
674 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
675 y1 = y - (PCB->MaxWidth - x);
676 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
677 glVertex3i (x0, y0, z);
678 glVertex3i (x1, y1, z);
681 static void
682 draw_dozen_cross (gint x, gint y, gint z)
684 gint x0, y0, x1, y1;
685 gdouble tan60 = sqrt (3);
687 x0 = x + (PCB->MaxHeight - y) / tan60;
688 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
689 x1 = x - y / tan60;
690 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
691 y0 = y + (PCB->MaxWidth - x) * tan60;
692 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
693 y1 = y - x * tan60;
694 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
695 glVertex3i (x0, y0, z);
696 glVertex3i (x1, y1, z);
698 x0 = x + (PCB->MaxHeight - y) * tan60;
699 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
700 x1 = x - y * tan60;
701 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
702 y0 = y + (PCB->MaxWidth - x) / tan60;
703 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
704 y1 = y - x / tan60;
705 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
706 glVertex3i (x0, y0, z);
707 glVertex3i (x1, y1, z);
709 x0 = x - (PCB->MaxHeight - y) / tan60;
710 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
711 x1 = x + y / tan60;
712 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
713 y0 = y + x * tan60;
714 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
715 y1 = y - (PCB->MaxWidth - x) * tan60;
716 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
717 glVertex3i (x0, y0, z);
718 glVertex3i (x1, y1, z);
720 x0 = x - (PCB->MaxHeight - y) * tan60;
721 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
722 x1 = x + y * tan60;
723 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
724 y0 = y + x / tan60;
725 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
726 y1 = y - (PCB->MaxWidth - x) / tan60;
727 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
728 glVertex3i (x0, y0, z);
729 glVertex3i (x1, y1, z);
732 static void
733 draw_crosshair (render_priv *priv)
735 gint x, y, z;
736 static int done_once = 0;
737 static GdkColor cross_color;
739 if (!done_once)
741 done_once = 1;
742 /* FIXME: when CrossColor changed from config */
743 ghid_map_color_string (Settings.CrossColor, &cross_color);
746 x = gport->crosshair_x;
747 y = gport->crosshair_y;
748 z = 0;
750 glEnable (GL_COLOR_LOGIC_OP);
751 glLogicOp (GL_XOR);
753 glColor3f (cross_color.red / 65535.,
754 cross_color.green / 65535.,
755 cross_color.blue / 65535.);
757 glBegin (GL_LINES);
759 draw_right_cross (x, y, z);
760 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
761 draw_slanted_cross (x, y, z);
762 if (Crosshair.shape == Dozen_Crosshair_Shape)
763 draw_dozen_cross (x, y, z);
765 glEnd ();
767 glDisable (GL_COLOR_LOGIC_OP);
770 void
771 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
773 render_priv *priv;
775 port->render_priv = priv = g_new0 (render_priv, 1);
777 priv->time_since_expose = g_timer_new ();
779 gtk_gl_init(argc, argv);
781 /* setup GL-context */
782 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
783 GDK_GL_MODE_STENCIL |
784 GDK_GL_MODE_DOUBLE);
785 if (!priv->glconfig)
787 printf ("Could not setup GL-context!\n");
788 return; /* Should we abort? */
791 /* Setup HID function pointers specific to the GL renderer*/
792 ghid_hid.end_layer = ghid_end_layer;
793 ghid_graphics.fill_pcb_polygon = ghid_fill_pcb_polygon;
794 ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
797 void
798 ghid_shutdown_renderer (GHidPort *port)
800 ghid_cancel_lead_user ();
801 g_free (port->render_priv);
802 port->render_priv = NULL;
805 void
806 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
808 render_priv *priv = port->render_priv;
810 gtk_widget_set_gl_capability (widget,
811 priv->glconfig,
812 NULL,
813 TRUE,
814 GDK_GL_RGBA_TYPE);
817 void
818 ghid_drawing_area_configure_hook (GHidPort *port)
822 gboolean
823 ghid_start_drawing (GHidPort *port)
825 GtkWidget *widget = port->drawing_area;
826 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
827 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
829 /* make GL-context "current" */
830 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
831 return FALSE;
833 port->render_priv->in_context = true;
835 return TRUE;
838 void
839 ghid_end_drawing (GHidPort *port)
841 GtkWidget *widget = port->drawing_area;
842 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
844 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
845 gdk_gl_drawable_swap_buffers (pGlDrawable);
846 else
847 glFlush ();
849 port->render_priv->in_context = false;
851 /* end drawing to current GL-context */
852 gdk_gl_drawable_gl_end (pGlDrawable);
855 void
856 ghid_screen_update (void)
860 #define Z_NEAR 3.0
861 gboolean
862 ghid_drawing_area_expose_cb (GtkWidget *widget,
863 GdkEventExpose *ev,
864 GHidPort *port)
866 render_priv *priv = port->render_priv;
867 GtkAllocation allocation;
868 BoxType region;
869 Coord min_x, min_y;
870 Coord max_x, max_y;
871 Coord new_x, new_y;
872 Coord min_depth;
873 Coord max_depth;
875 gtk_widget_get_allocation (widget, &allocation);
877 ghid_start_drawing (port);
878 hidgl_start_render ();
880 /* If we don't have any stencil bits available,
881 we can't use the hidgl polygon drawing routine */
882 /* TODO: We could use the GLU tessellator though */
883 if (hidgl_stencil_bits() == 0)
884 ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon;
886 glEnable (GL_BLEND);
887 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
889 glViewport (0, 0, allocation.width, allocation.height);
891 glEnable (GL_SCISSOR_TEST);
892 glScissor (ev->area.x,
893 allocation.height - ev->area.height - ev->area.y,
894 ev->area.width, ev->area.height);
896 glMatrixMode (GL_PROJECTION);
897 glLoadIdentity ();
898 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
899 glMatrixMode (GL_MODELVIEW);
900 glLoadIdentity ();
901 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
902 glMultMatrixf ((GLfloat *)view_matrix);
903 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
904 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
905 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
906 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
907 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
908 -port->view.x0,
909 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
910 -port->view.y0, 0);
911 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
913 glEnable (GL_STENCIL_TEST);
914 glClearColor (port->offlimits_color.red / 65535.,
915 port->offlimits_color.green / 65535.,
916 port->offlimits_color.blue / 65535.,
917 1.);
918 glStencilMask (~0);
919 glClearStencil (0);
920 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
921 hidgl_reset_stencil_usage ();
923 /* Disable the stencil test until we need it - otherwise it gets dirty */
924 glDisable (GL_STENCIL_TEST);
925 glStencilMask (0);
926 glStencilFunc (GL_ALWAYS, 0, 0);
928 /* Test the 8 corners of a cube spanning the event */
929 min_depth = -50; /* FIXME */
930 max_depth = 0; /* FIXME */
932 ghid_unproject_to_z_plane (ev->area.x,
933 ev->area.y,
934 min_depth, &new_x, &new_y);
935 max_x = min_x = new_x;
936 max_y = min_y = new_y;
938 ghid_unproject_to_z_plane (ev->area.x,
939 ev->area.y,
940 max_depth, &new_x, &new_y);
941 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
942 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
944 /* */
945 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
946 ev->area.y,
947 min_depth, &new_x, &new_y);
948 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
949 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
951 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
952 max_depth, &new_x, &new_y);
953 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
954 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
956 /* */
957 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
958 ev->area.y + ev->area.height,
959 min_depth, &new_x, &new_y);
960 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
961 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
963 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
964 ev->area.y + ev->area.height,
965 max_depth, &new_x, &new_y);
966 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
967 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
969 /* */
970 ghid_unproject_to_z_plane (ev->area.x,
971 ev->area.y + ev->area.height,
972 min_depth,
973 &new_x, &new_y);
974 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
975 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
977 ghid_unproject_to_z_plane (ev->area.x,
978 ev->area.y + ev->area.height,
979 max_depth,
980 &new_x, &new_y);
981 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
982 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
984 region.X1 = min_x; region.X2 = max_x + 1;
985 region.Y1 = min_y; region.Y2 = max_y + 1;
987 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
988 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
989 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
990 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
992 glColor3f (port->bg_color.red / 65535.,
993 port->bg_color.green / 65535.,
994 port->bg_color.blue / 65535.);
996 glBegin (GL_QUADS);
997 glVertex3i (0, 0, -50);
998 glVertex3i (PCB->MaxWidth, 0, -50);
999 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
1000 glVertex3i (0, PCB->MaxHeight, -50);
1001 glEnd ();
1003 ghid_draw_bg_image ();
1005 ghid_invalidate_current_gc ();
1006 hid_expose_callback (&ghid_hid, &region, 0);
1007 hidgl_flush_triangles (&buffer);
1009 ghid_draw_grid (&region);
1011 ghid_invalidate_current_gc ();
1013 DrawAttached ();
1014 DrawMark ();
1015 hidgl_flush_triangles (&buffer);
1017 draw_crosshair (priv);
1018 hidgl_flush_triangles (&buffer);
1020 draw_lead_user (priv);
1022 hidgl_finish_render ();
1023 ghid_end_drawing (port);
1025 g_timer_start (priv->time_since_expose);
1027 return FALSE;
1030 /* This realize callback is used to work around a crash bug in some mesa
1031 * versions (observed on a machine running the intel i965 driver. It isn't
1032 * obvious why it helps, but somehow fiddling with the GL context here solves
1033 * the issue. The problem appears to have been fixed in recent mesa versions.
1035 void
1036 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1038 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1039 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1041 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1042 return;
1044 gdk_gl_drawable_gl_end (gldrawable);
1045 return;
1048 gboolean
1049 ghid_pinout_preview_expose (GtkWidget *widget,
1050 GdkEventExpose *ev)
1052 GdkGLContext* pGlContext = gtk_widget_get_gl_context (widget);
1053 GdkGLDrawable* pGlDrawable = gtk_widget_get_gl_drawable (widget);
1054 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
1055 GtkAllocation allocation;
1056 view_data save_view;
1057 int save_width, save_height;
1058 Coord save_max_width;
1059 Coord save_max_height;
1060 double xz, yz;
1062 save_view = gport->view;
1063 save_width = gport->width;
1064 save_height = gport->height;
1065 save_max_width = PCB->MaxWidth;
1066 save_max_height = PCB->MaxHeight;
1068 /* Setup zoom factor for drawing routines */
1070 gtk_widget_get_allocation (widget, &allocation);
1071 xz = (double) pinout->x_max / allocation.width;
1072 yz = (double) pinout->y_max / allocation.height;
1073 if (xz > yz)
1074 gport->view.coord_per_px = xz;
1075 else
1076 gport->view.coord_per_px = yz;
1078 gport->width = allocation.width;
1079 gport->height = allocation.height;
1080 gport->view.width = allocation.width * gport->view.coord_per_px;
1081 gport->view.height = allocation.height * gport->view.coord_per_px;
1082 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
1083 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
1084 PCB->MaxWidth = pinout->x_max;
1085 PCB->MaxHeight = pinout->y_max;
1087 /* make GL-context "current" */
1088 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) {
1089 return FALSE;
1091 hidgl_start_render ();
1092 gport->render_priv->in_context = true;
1094 glEnable (GL_BLEND);
1095 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1097 glViewport (0, 0, allocation.width, allocation.height);
1099 glEnable (GL_SCISSOR_TEST);
1100 glScissor (ev->area.x,
1101 allocation.height - ev->area.height - ev->area.y,
1102 ev->area.width, ev->area.height);
1104 glMatrixMode (GL_PROJECTION);
1105 glLoadIdentity ();
1106 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1107 glMatrixMode (GL_MODELVIEW);
1108 glLoadIdentity ();
1109 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1111 glClearColor (gport->bg_color.red / 65535.,
1112 gport->bg_color.green / 65535.,
1113 gport->bg_color.blue / 65535.,
1114 1.);
1115 glStencilMask (~0);
1116 glClearStencil (0);
1117 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1118 hidgl_reset_stencil_usage ();
1120 /* call the drawing routine */
1121 ghid_invalidate_current_gc ();
1122 glPushMatrix ();
1123 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1124 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1125 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1126 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1127 -gport->view.x0,
1128 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1129 -gport->view.y0, 0);
1131 hid_expose_callback (&ghid_hid, NULL, &pinout->element);
1132 hidgl_flush_triangles (&buffer);
1133 glPopMatrix ();
1135 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1136 gdk_gl_drawable_swap_buffers (pGlDrawable);
1137 else
1138 glFlush ();
1140 hidgl_finish_render ();
1142 /* end drawing to current GL-context */
1143 gport->render_priv->in_context = false;
1144 gdk_gl_drawable_gl_end (pGlDrawable);
1146 gport->view = save_view;
1147 gport->width = save_width;
1148 gport->height = save_height;
1149 PCB->MaxWidth = save_max_width;
1150 PCB->MaxHeight = save_max_height;
1152 return FALSE;
1156 GdkPixmap *
1157 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
1159 GdkGLConfig *glconfig;
1160 GdkPixmap *pixmap;
1161 GdkGLPixmap *glpixmap;
1162 GdkGLContext* glcontext;
1163 GdkGLDrawable* gldrawable;
1164 view_data save_view;
1165 int save_width, save_height;
1166 BoxType region;
1168 save_view = gport->view;
1169 save_width = gport->width;
1170 save_height = gport->height;
1172 /* Setup rendering context for drawing routines
1175 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
1176 GDK_GL_MODE_STENCIL |
1177 GDK_GL_MODE_SINGLE);
1179 pixmap = gdk_pixmap_new (NULL, width, height, depth);
1180 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
1181 gldrawable = GDK_GL_DRAWABLE (glpixmap);
1182 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
1184 /* Setup zoom factor for drawing routines */
1186 gport->view.coord_per_px = zoom;
1187 gport->width = width;
1188 gport->height = height;
1189 gport->view.width = width * gport->view.coord_per_px;
1190 gport->view.height = height * gport->view.coord_per_px;
1191 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
1192 gport->view.x0 -= gport->view.height / 2;
1193 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
1194 gport->view.y0 -= gport->view.width / 2;
1196 /* make GL-context "current" */
1197 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
1198 return NULL;
1200 hidgl_start_render ();
1201 gport->render_priv->in_context = true;
1203 glEnable (GL_BLEND);
1204 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1206 glViewport (0, 0, width, height);
1208 glEnable (GL_SCISSOR_TEST);
1209 glScissor (0, 0, width, height);
1211 glMatrixMode (GL_PROJECTION);
1212 glLoadIdentity ();
1213 glOrtho (0, width, height, 0, -100000, 100000);
1214 glMatrixMode (GL_MODELVIEW);
1215 glLoadIdentity ();
1216 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1218 glClearColor (gport->bg_color.red / 65535.,
1219 gport->bg_color.green / 65535.,
1220 gport->bg_color.blue / 65535.,
1221 1.);
1222 glStencilMask (~0);
1223 glClearStencil (0);
1224 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1225 hidgl_reset_stencil_usage ();
1227 /* call the drawing routine */
1228 ghid_invalidate_current_gc ();
1229 glPushMatrix ();
1230 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1231 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1232 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1233 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1234 -gport->view.x0,
1235 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1236 -gport->view.y0, 0);
1238 region.X1 = MIN(Px(0), Px(gport->width + 1));
1239 region.Y1 = MIN(Py(0), Py(gport->height + 1));
1240 region.X2 = MAX(Px(0), Px(gport->width + 1));
1241 region.Y2 = MAX(Py(0), Py(gport->height + 1));
1243 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1244 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1245 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1246 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1248 hid_expose_callback (&ghid_hid, &region, NULL);
1249 hidgl_flush_triangles (&buffer);
1250 glPopMatrix ();
1252 glFlush ();
1254 hidgl_finish_render ();
1256 /* end drawing to current GL-context */
1257 gport->render_priv->in_context = false;
1258 gdk_gl_drawable_gl_end (gldrawable);
1260 gdk_pixmap_unset_gl_capability (pixmap);
1262 g_object_unref (glconfig);
1263 g_object_unref (glcontext);
1265 gport->view = save_view;
1266 gport->width = save_width;
1267 gport->height = save_height;
1269 return pixmap;
1272 HID *
1273 ghid_request_debug_draw (void)
1275 GHidPort *port = gport;
1276 GtkWidget *widget = port->drawing_area;
1277 GtkAllocation allocation;
1279 gtk_widget_get_allocation (widget, &allocation);
1281 ghid_start_drawing (port);
1282 hidgl_start_render ();
1284 glViewport (0, 0, allocation.width, allocation.height);
1286 glMatrixMode (GL_PROJECTION);
1287 glLoadIdentity ();
1288 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
1289 glMatrixMode (GL_MODELVIEW);
1290 glLoadIdentity ();
1291 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1293 ghid_invalidate_current_gc ();
1295 /* Setup stenciling */
1296 glDisable (GL_STENCIL_TEST);
1298 glPushMatrix ();
1299 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1300 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1301 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1302 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1303 -port->view.x0,
1304 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1305 -port->view.y0, 0);
1307 return &ghid_hid;
1310 void
1311 ghid_flush_debug_draw (void)
1313 GtkWidget *widget = gport->drawing_area;
1314 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1316 hidgl_flush_triangles (&buffer);
1318 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1319 gdk_gl_drawable_swap_buffers (pGlDrawable);
1320 else
1321 glFlush ();
1324 void
1325 ghid_finish_debug_draw (void)
1327 hidgl_flush_triangles (&buffer);
1328 glPopMatrix ();
1330 hidgl_finish_render ();
1331 ghid_end_drawing (gport);
1334 static float
1335 determinant_2x2 (float m[2][2])
1337 float det;
1338 det = m[0][0] * m[1][1] -
1339 m[0][1] * m[1][0];
1340 return det;
1343 #if 0
1344 static float
1345 determinant_4x4 (float m[4][4])
1347 float det;
1348 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] -
1349 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
1350 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
1351 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
1352 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
1353 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
1354 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
1355 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
1356 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
1357 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
1358 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
1359 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
1360 return det;
1362 #endif
1364 static void
1365 invert_2x2 (float m[2][2], float out[2][2])
1367 float scale = 1 / determinant_2x2 (m);
1368 out[0][0] = m[1][1] * scale;
1369 out[0][1] = -m[0][1] * scale;
1370 out[1][0] = -m[1][0] * scale;
1371 out[1][1] = m[0][0] * scale;
1374 #if 0
1375 static void
1376 invert_4x4 (float m[4][4], float out[4][4])
1378 float scale = 1 / determinant_4x4 (m);
1380 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
1381 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
1382 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
1383 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
1384 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
1385 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
1386 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
1387 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
1388 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
1389 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
1390 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
1391 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
1392 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
1393 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
1394 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
1395 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
1396 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
1397 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
1398 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
1399 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
1400 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
1401 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
1402 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
1403 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
1404 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
1405 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
1406 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
1407 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
1408 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
1409 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
1410 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
1411 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
1412 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
1413 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
1414 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
1415 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
1416 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
1417 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
1418 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
1419 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
1420 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
1421 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
1422 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
1423 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
1424 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
1425 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
1426 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
1427 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
1429 #endif
1432 static void
1433 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
1435 float mat[2][2];
1436 float inv_mat[2][2];
1437 float x, y;
1440 ex = view_matrix[0][0] * vx +
1441 view_matrix[0][1] * vy +
1442 view_matrix[0][2] * vz +
1443 view_matrix[0][3] * 1;
1444 ey = view_matrix[1][0] * vx +
1445 view_matrix[1][1] * vy +
1446 view_matrix[1][2] * vz +
1447 view_matrix[1][3] * 1;
1448 UNKNOWN ez = view_matrix[2][0] * vx +
1449 view_matrix[2][1] * vy +
1450 view_matrix[2][2] * vz +
1451 view_matrix[2][3] * 1;
1453 ex - view_matrix[0][3] * 1
1454 - view_matrix[0][2] * vz
1455 = view_matrix[0][0] * vx +
1456 view_matrix[0][1] * vy;
1458 ey - view_matrix[1][3] * 1
1459 - view_matrix[1][2] * vz
1460 = view_matrix[1][0] * vx +
1461 view_matrix[1][1] * vy;
1464 /* NB: last_modelview_matrix is transposed in memory! */
1465 x = (float)ex - last_modelview_matrix[3][0] * 1
1466 - last_modelview_matrix[2][0] * pcb_z;
1468 y = (float)ey - last_modelview_matrix[3][1] * 1
1469 - last_modelview_matrix[2][1] * pcb_z;
1472 x = view_matrix[0][0] * vx +
1473 view_matrix[0][1] * vy;
1475 y = view_matrix[1][0] * vx +
1476 view_matrix[1][1] * vy;
1478 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1479 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1482 mat[0][0] = last_modelview_matrix[0][0];
1483 mat[0][1] = last_modelview_matrix[1][0];
1484 mat[1][0] = last_modelview_matrix[0][1];
1485 mat[1][1] = last_modelview_matrix[1][1];
1487 /* if (determinant_2x2 (mat) < 0.00001) */
1488 /* printf ("Determinant is quite small\n"); */
1490 invert_2x2 (mat, inv_mat);
1492 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
1493 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
1497 bool
1498 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
1500 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
1502 return true;
1505 bool
1506 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
1508 /* NB: last_modelview_matrix is transposed in memory */
1509 float w = last_modelview_matrix[0][3] * (float)pcb_x +
1510 last_modelview_matrix[1][3] * (float)pcb_y +
1511 last_modelview_matrix[2][3] * 0. +
1512 last_modelview_matrix[3][3] * 1.;
1514 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
1515 last_modelview_matrix[1][0] * (float)pcb_y +
1516 last_modelview_matrix[2][0] * 0. +
1517 last_modelview_matrix[3][0] * 1.) / w;
1518 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
1519 last_modelview_matrix[1][1] * (float)pcb_y +
1520 last_modelview_matrix[2][1] * 0. +
1521 last_modelview_matrix[3][1] * 1.) / w;
1523 return true;
1526 void
1527 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
1529 global_view_2d = view_2d;
1530 ghid_invalidate_all ();
1533 void
1534 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
1536 #ifdef DEBUG_ROTATE
1537 int row, column;
1538 #endif
1540 build_rotmatrix (view_matrix, quarternion);
1542 #ifdef DEBUG_ROTATE
1543 for (row = 0; row < 4; row++) {
1544 printf ("[ %f", view_matrix[row][0]);
1545 for (column = 1; column < 4; column++) {
1546 printf (",\t%f", view_matrix[row][column]);
1548 printf ("\t]\n");
1550 printf ("\n");
1551 #endif
1553 ghid_invalidate_all ();
1557 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1558 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1559 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1560 #define LEAD_USER_ARC_COUNT 3
1561 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1562 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1563 #define LEAD_USER_COLOR_R 1.
1564 #define LEAD_USER_COLOR_G 1.
1565 #define LEAD_USER_COLOR_B 0.
1567 static void
1568 draw_lead_user (render_priv *priv)
1570 int i;
1571 double radius = priv->lead_user_radius;
1572 double width = MM_TO_COORD (LEAD_USER_WIDTH);
1573 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
1575 if (!priv->lead_user)
1576 return;
1578 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
1579 glEnable (GL_COLOR_LOGIC_OP);
1580 glLogicOp (GL_XOR);
1581 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
1584 /* arcs at the approrpriate radii */
1586 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
1588 if (radius < width)
1589 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1591 /* Draw an arc at radius */
1592 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
1593 radius, radius, 0, 360, gport->view.coord_per_px);
1596 hidgl_flush_triangles (&buffer);
1597 glPopAttrib ();
1600 gboolean
1601 lead_user_cb (gpointer data)
1603 render_priv *priv = data;
1604 Coord step;
1605 double elapsed_time;
1607 /* Queue a redraw */
1608 ghid_invalidate_all ();
1610 /* Update radius */
1611 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
1612 g_timer_start (priv->lead_user_timer);
1614 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
1615 if (priv->lead_user_radius > step)
1616 priv->lead_user_radius -= step;
1617 else
1618 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1620 return TRUE;
1623 void
1624 ghid_lead_user_to_location (Coord x, Coord y)
1626 render_priv *priv = gport->render_priv;
1628 ghid_cancel_lead_user ();
1630 priv->lead_user = true;
1631 priv->lead_user_x = x;
1632 priv->lead_user_y = y;
1633 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1634 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
1635 priv->lead_user_timer = g_timer_new ();
1638 void
1639 ghid_cancel_lead_user (void)
1641 render_priv *priv = gport->render_priv;
1643 if (priv->lead_user_timeout)
1644 g_source_remove (priv->lead_user_timeout);
1646 if (priv->lead_user_timer)
1647 g_timer_destroy (priv->lead_user_timer);
1649 if (priv->lead_user)
1650 ghid_invalidate_all ();
1652 priv->lead_user_timeout = 0;
1653 priv->lead_user_timer = NULL;
1654 priv->lead_user = false;