Move some fields from the HID* structure to HID_DRAW* and HID_DRAW_CLASS*
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blob4690dd540d36aacfa1fa8d953f2f345df874d3f3
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;
38 extern HID_DRAW_CLASS ghid_graphics_class;
40 static hidGC current_gc = NULL;
42 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
44 #define USE_GC(gc) if (!use_gc(gc)) return
46 static enum mask_mode cur_mask = HID_MASK_OFF;
47 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
48 {0.0, 1.0, 0.0, 0.0},
49 {0.0, 0.0, 1.0, 0.0},
50 {0.0, 0.0, 0.0, 1.0}};
51 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0},
52 {0.0, 1.0, 0.0, 0.0},
53 {0.0, 0.0, 1.0, 0.0},
54 {0.0, 0.0, 0.0, 1.0}};
55 static int global_view_2d = 1;
57 typedef struct render_priv {
58 GdkGLConfig *glconfig;
59 bool trans_lines;
60 bool in_context;
61 int subcomposite_stencil_bit;
62 char *current_colorname;
63 double current_alpha_mult;
64 GTimer *time_since_expose;
66 /* Feature for leading the user to a particular location */
67 guint lead_user_timeout;
68 GTimer *lead_user_timer;
69 bool lead_user;
70 Coord lead_user_radius;
71 Coord lead_user_x;
72 Coord lead_user_y;
74 hidGC crosshair_gc;
75 } render_priv;
77 typedef struct gtk_gc_struct
79 struct hid_gc_struct hid_gc; /* Parent */
81 const char *colorname;
82 double alpha_mult;
83 Coord width;
84 gint cap, join;
85 } *gtkGC;
87 static void draw_lead_user (render_priv *priv);
88 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y);
91 static void
92 start_subcomposite (void)
94 render_priv *priv = gport->render_priv;
95 int stencil_bit;
97 /* Flush out any existing geoemtry to be rendered */
98 hidgl_flush_triangles (&buffer);
100 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
101 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
103 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
104 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
105 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */
107 priv->subcomposite_stencil_bit = stencil_bit;
110 static void
111 end_subcomposite (void)
113 render_priv *priv = gport->render_priv;
115 /* Flush out any existing geoemtry to be rendered */
116 hidgl_flush_triangles (&buffer);
118 hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */
120 glStencilMask (0);
121 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */
122 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
124 priv->subcomposite_stencil_bit = 0;
129 ghid_set_layer (const char *name, int group, int empty)
131 render_priv *priv = gport->render_priv;
132 int idx = group;
133 if (idx >= 0 && idx < max_group)
135 int n = PCB->LayerGroups.Number[group];
136 for (idx = 0; idx < n-1; idx ++)
138 int ni = PCB->LayerGroups.Entries[group][idx];
139 if (ni >= 0 && ni < max_copper_layer + 2
140 && PCB->Data->Layer[ni].On)
141 break;
143 idx = PCB->LayerGroups.Entries[group][idx];
146 end_subcomposite ();
147 start_subcomposite ();
149 if (idx >= 0 && idx < max_copper_layer + 2)
151 priv->trans_lines = true;
152 return PCB->Data->Layer[idx].On;
154 if (idx < 0)
156 switch (SL_TYPE (idx))
158 case SL_INVISIBLE:
159 return PCB->InvisibleObjectsOn;
160 case SL_MASK:
161 if (SL_MYSIDE (idx))
162 return TEST_FLAG (SHOWMASKFLAG, PCB);
163 return 0;
164 case SL_SILK:
165 priv->trans_lines = true;
166 if (SL_MYSIDE (idx))
167 return PCB->ElementOn;
168 return 0;
169 case SL_ASSY:
170 return 0;
171 case SL_PDRILL:
172 case SL_UDRILL:
173 return 1;
174 case SL_RATS:
175 if (PCB->RatOn)
176 priv->trans_lines = true;
177 return PCB->RatOn;
180 return 0;
183 static void
184 ghid_end_layer (void)
186 end_subcomposite ();
189 void
190 ghid_destroy_gc (hidGC gc)
192 g_free (gc);
195 hidGC
196 ghid_make_gc (void)
198 hidGC gc = (hidGC) g_new0 (struct gtk_gc_struct, 1);
199 gtkGC gtk_gc = (gtkGC)gc;
201 gc->hid = &ghid_hid;
202 gc->hid_draw = &ghid_graphics;
204 gtk_gc->colorname = Settings.BackgroundColor;
205 gtk_gc->alpha_mult = 1.0;
207 return gc;
210 static void
211 ghid_draw_grid (BoxType *drawn_area)
213 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
214 return;
216 if (gdk_color_parse (Settings.GridColor, &gport->grid_color))
218 gport->grid_color.red ^= gport->bg_color.red;
219 gport->grid_color.green ^= gport->bg_color.green;
220 gport->grid_color.blue ^= gport->bg_color.blue;
223 glEnable (GL_COLOR_LOGIC_OP);
224 glLogicOp (GL_XOR);
226 glColor3f (gport->grid_color.red / 65535.,
227 gport->grid_color.green / 65535.,
228 gport->grid_color.blue / 65535.);
230 hidgl_draw_grid (drawn_area);
232 glDisable (GL_COLOR_LOGIC_OP);
235 static void
236 ghid_draw_bg_image (void)
238 static GLuint texture_handle = 0;
240 if (!ghidgui->bg_pixbuf)
241 return;
243 if (texture_handle == 0)
245 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf);
246 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf);
247 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf);
248 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf);
249 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf);
250 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf);
252 g_warn_if_fail (bits_per_sample == 8);
253 g_warn_if_fail (rowstride == width * n_channels);
255 glGenTextures (1, &texture_handle);
256 glBindTexture (GL_TEXTURE_2D, texture_handle);
258 /* XXX: We should proabbly determine what the maxmimum texture supported is,
259 * and if our image is larger, shrink it down using GDK pixbuf routines
260 * rather than having it fail below.
263 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
264 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels);
267 glBindTexture (GL_TEXTURE_2D, texture_handle);
269 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
270 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
271 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
272 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
273 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
274 glEnable (GL_TEXTURE_2D);
276 /* Render a quad with the background as a texture */
278 glBegin (GL_QUADS);
279 glTexCoord2d (0., 0.);
280 glVertex3i (0, 0, 0);
281 glTexCoord2d (1., 0.);
282 glVertex3i (PCB->MaxWidth, 0, 0);
283 glTexCoord2d (1., 1.);
284 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0);
285 glTexCoord2d (0., 1.);
286 glVertex3i (0, PCB->MaxHeight, 0);
287 glEnd ();
289 glDisable (GL_TEXTURE_2D);
292 void
293 ghid_use_mask (enum mask_mode mode)
295 static int stencil_bit = 0;
297 if (mode == cur_mask)
298 return;
300 /* Flush out any existing geoemtry to be rendered */
301 hidgl_flush_triangles (&buffer);
303 switch (mode)
305 case HID_MASK_BEFORE:
306 /* The HID asks not to receive this mask type, so warn if we get it */
307 g_return_if_reached ();
309 case HID_MASK_CLEAR:
310 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
311 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
312 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */
313 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
314 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */
315 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */
316 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */
317 break;
319 case HID_MASK_AFTER:
320 /* Drawing operations as masked to areas where the stencil buffer is '0' */
321 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
322 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */
323 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */
324 break;
326 case HID_MASK_OFF:
327 /* Disable stenciling */
328 hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */
329 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */
330 break;
332 cur_mask = mode;
336 /* Config helper functions for when the user changes color preferences.
337 | set_special colors used in the gtkhid.
339 static void
340 set_special_grid_color (void)
342 if (!gport->colormap)
343 return;
344 gport->grid_color.red ^= gport->bg_color.red;
345 gport->grid_color.green ^= gport->bg_color.green;
346 gport->grid_color.blue ^= gport->bg_color.blue;
349 void
350 ghid_set_special_colors (HID_Attribute * ha)
352 if (!ha->name || !ha->value)
353 return;
354 if (!strcmp (ha->name, "background-color"))
356 ghid_map_color_string (*(char **) ha->value, &gport->bg_color);
357 set_special_grid_color ();
359 else if (!strcmp (ha->name, "off-limit-color"))
361 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color);
363 else if (!strcmp (ha->name, "grid-color"))
365 ghid_map_color_string (*(char **) ha->value, &gport->grid_color);
366 set_special_grid_color ();
370 typedef struct
372 int color_set;
373 GdkColor color;
374 double red;
375 double green;
376 double blue;
377 } ColorCache;
379 static void
380 set_gl_color_for_gc (hidGC gc)
382 gtkGC gtk_gc = (gtkGC)gc;
383 render_priv *priv = gport->render_priv;
384 static void *cache = NULL;
385 hidval cval;
386 ColorCache *cc;
387 double r, g, b, a;
389 if (priv->current_colorname != NULL &&
390 strcmp (priv->current_colorname, gtk_gc->colorname) == 0 &&
391 priv->current_alpha_mult == gtk_gc->alpha_mult)
392 return;
394 free (priv->current_colorname);
395 priv->current_colorname = strdup (gtk_gc->colorname);
396 priv->current_alpha_mult = gtk_gc->alpha_mult;
398 if (gport->colormap == NULL)
399 gport->colormap = gtk_widget_get_colormap (gport->top_window);
400 if (strcmp (gtk_gc->colorname, "erase") == 0)
402 r = gport->bg_color.red / 65535.;
403 g = gport->bg_color.green / 65535.;
404 b = gport->bg_color.blue / 65535.;
405 a = 1.0;
407 else if (strcmp (gtk_gc->colorname, "drill") == 0)
409 r = gport->offlimits_color.red / 65535.;
410 g = gport->offlimits_color.green / 65535.;
411 b = gport->offlimits_color.blue / 65535.;
412 a = 0.85;
414 else
416 if (hid_cache_color (0, gtk_gc->colorname, &cval, &cache))
417 cc = (ColorCache *) cval.ptr;
418 else
420 cc = (ColorCache *) malloc (sizeof (ColorCache));
421 memset (cc, 0, sizeof (*cc));
422 cval.ptr = cc;
423 hid_cache_color (1, gtk_gc->colorname, &cval, &cache);
426 if (!cc->color_set)
428 if (gdk_color_parse (gtk_gc->colorname, &cc->color))
429 gdk_color_alloc (gport->colormap, &cc->color);
430 else
431 gdk_color_white (gport->colormap, &cc->color);
432 cc->red = cc->color.red / 65535.;
433 cc->green = cc->color.green / 65535.;
434 cc->blue = cc->color.blue / 65535.;
435 cc->color_set = 1;
437 r = cc->red;
438 g = cc->green;
439 b = cc->blue;
440 a = 0.7;
442 if (1) {
443 double maxi, mult;
444 a *= gtk_gc->alpha_mult;
445 if (!priv->trans_lines)
446 a = 1.0;
447 maxi = r;
448 if (g > maxi) maxi = g;
449 if (b > maxi) maxi = b;
450 mult = MIN (1 / a, 1 / maxi);
451 #if 1
452 r = r * mult;
453 g = g * mult;
454 b = b * mult;
455 #endif
458 if(!priv->in_context)
459 return;
461 hidgl_flush_triangles (&buffer);
462 glColor4d (r, g, b, a);
465 void
466 ghid_set_color (hidGC gc, const char *name)
468 gtkGC gtk_gc = (gtkGC)gc;
470 gtk_gc->colorname = name;
471 set_gl_color_for_gc (gc);
474 void
475 ghid_set_alpha_mult (hidGC gc, double alpha_mult)
477 gtkGC gtk_gc = (gtkGC)gc;
479 gtk_gc->alpha_mult = alpha_mult;
480 set_gl_color_for_gc (gc);
483 void
484 ghid_set_line_cap (hidGC gc, EndCapStyle style)
486 gtkGC gtk_gc = (gtkGC)gc;
488 gtk_gc->cap = style;
491 void
492 ghid_set_line_width (hidGC gc, Coord width)
494 gtkGC gtk_gc = (gtkGC)gc;
496 gtk_gc->width = width;
500 void
501 ghid_set_draw_xor (hidGC gc, int xor)
503 /* NOT IMPLEMENTED */
505 /* Only presently called when setting up a crosshair GC.
506 * We manage our own drawing model for that anyway. */
509 void
510 ghid_set_draw_faded (hidGC gc, int faded)
512 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded);
515 void
516 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
518 printf ("ghid_set_line_cap_angle() -- not implemented\n");
521 static void
522 ghid_invalidate_current_gc (void)
524 current_gc = NULL;
527 static int
528 use_gc (hidGC gc)
530 if (gc->hid != &ghid_hid)
532 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n");
533 abort ();
536 if (current_gc == gc)
537 return 1;
539 current_gc = gc;
541 set_gl_color_for_gc (gc);
542 return 1;
545 void
546 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
548 gtkGC gtk_gc = (gtkGC)gc;
549 USE_GC (gc);
551 hidgl_draw_line (gtk_gc->cap, gtk_gc->width, x1, y1, x2, y2, gport->view.coord_per_px);
554 void
555 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius,
556 Angle start_angle, Angle delta_angle)
558 gtkGC gtk_gc = (gtkGC)gc;
559 USE_GC (gc);
561 hidgl_draw_arc (gtk_gc->width, cx, cy, xradius, yradius,
562 start_angle, delta_angle, gport->view.coord_per_px);
565 void
566 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
568 USE_GC (gc);
570 hidgl_draw_rect (x1, y1, x2, y2);
574 void
575 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
577 USE_GC (gc);
579 hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px);
583 void
584 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
586 USE_GC (gc);
588 hidgl_fill_polygon (n_coords, x, y);
591 void
592 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
594 USE_GC (gc);
596 hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px);
599 void
600 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box)
602 common_thindraw_pcb_polygon (gc, poly, clip_box);
603 ghid_set_alpha_mult (gc, 0.25);
604 hid_draw_fill_pcb_polygon (gc, poly, clip_box);
605 ghid_set_alpha_mult (gc, 1.0);
608 void
609 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
611 USE_GC (gc);
613 hidgl_fill_rect (x1, y1, x2, y2);
616 void
617 ghid_invalidate_lr (int left, int right, int top, int bottom)
619 ghid_invalidate_all ();
622 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
623 void
624 ghid_invalidate_all ()
626 render_priv *priv = gport->render_priv;
627 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL);
629 ghid_draw_area_update (gport, NULL);
631 if (elapsed > MAX_ELAPSED)
632 gdk_window_process_all_updates ();
635 void
636 ghid_notify_crosshair_change (bool changes_complete)
638 /* We sometimes get called before the GUI is up */
639 if (gport->drawing_area == NULL)
640 return;
642 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
643 ghid_invalidate_all ();
646 void
647 ghid_notify_mark_change (bool changes_complete)
649 /* We sometimes get called before the GUI is up */
650 if (gport->drawing_area == NULL)
651 return;
653 /* FIXME: We could just invalidate the bounds of the mark? */
654 ghid_invalidate_all ();
657 static void
658 draw_right_cross (gint x, gint y, gint z)
660 glVertex3i (x, 0, z);
661 glVertex3i (x, PCB->MaxHeight, z);
662 glVertex3i (0, y, z);
663 glVertex3i (PCB->MaxWidth, y, z);
666 static void
667 draw_slanted_cross (gint x, gint y, gint z)
669 gint x0, y0, x1, y1;
671 x0 = x + (PCB->MaxHeight - y);
672 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
673 x1 = x - y;
674 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
675 y0 = y + (PCB->MaxWidth - x);
676 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
677 y1 = y - x;
678 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
679 glVertex3i (x0, y0, z);
680 glVertex3i (x1, y1, z);
682 x0 = x - (PCB->MaxHeight - y);
683 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
684 x1 = x + y;
685 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
686 y0 = y + x;
687 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
688 y1 = y - (PCB->MaxWidth - x);
689 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
690 glVertex3i (x0, y0, z);
691 glVertex3i (x1, y1, z);
694 static void
695 draw_dozen_cross (gint x, gint y, gint z)
697 gint x0, y0, x1, y1;
698 gdouble tan60 = sqrt (3);
700 x0 = x + (PCB->MaxHeight - y) / tan60;
701 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
702 x1 = x - y / tan60;
703 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
704 y0 = y + (PCB->MaxWidth - x) * tan60;
705 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
706 y1 = y - x * tan60;
707 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
708 glVertex3i (x0, y0, z);
709 glVertex3i (x1, y1, z);
711 x0 = x + (PCB->MaxHeight - y) * tan60;
712 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
713 x1 = x - y * tan60;
714 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
715 y0 = y + (PCB->MaxWidth - x) / tan60;
716 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
717 y1 = y - x / tan60;
718 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
719 glVertex3i (x0, y0, z);
720 glVertex3i (x1, y1, z);
722 x0 = x - (PCB->MaxHeight - y) / tan60;
723 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
724 x1 = x + y / tan60;
725 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
726 y0 = y + x * tan60;
727 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
728 y1 = y - (PCB->MaxWidth - x) * tan60;
729 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
730 glVertex3i (x0, y0, z);
731 glVertex3i (x1, y1, z);
733 x0 = x - (PCB->MaxHeight - y) * tan60;
734 x0 = MAX(0, MIN (x0, PCB->MaxWidth));
735 x1 = x + y * tan60;
736 x1 = MAX(0, MIN (x1, PCB->MaxWidth));
737 y0 = y + x / tan60;
738 y0 = MAX(0, MIN (y0, PCB->MaxHeight));
739 y1 = y - (PCB->MaxWidth - x) / tan60;
740 y1 = MAX(0, MIN (y1, PCB->MaxHeight));
741 glVertex3i (x0, y0, z);
742 glVertex3i (x1, y1, z);
745 static void
746 draw_crosshair (render_priv *priv)
748 gint x, y, z;
749 static int done_once = 0;
750 static GdkColor cross_color;
752 if (!done_once)
754 done_once = 1;
755 /* FIXME: when CrossColor changed from config */
756 ghid_map_color_string (Settings.CrossColor, &cross_color);
759 x = gport->crosshair_x;
760 y = gport->crosshair_y;
761 z = 0;
763 glEnable (GL_COLOR_LOGIC_OP);
764 glLogicOp (GL_XOR);
766 glColor3f (cross_color.red / 65535.,
767 cross_color.green / 65535.,
768 cross_color.blue / 65535.);
770 glBegin (GL_LINES);
772 draw_right_cross (x, y, z);
773 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
774 draw_slanted_cross (x, y, z);
775 if (Crosshair.shape == Dozen_Crosshair_Shape)
776 draw_dozen_cross (x, y, z);
778 glEnd ();
780 glDisable (GL_COLOR_LOGIC_OP);
783 void
784 ghid_init_renderer (int *argc, char ***argv, GHidPort *port)
786 render_priv *priv;
788 port->render_priv = priv = g_new0 (render_priv, 1);
789 port->render_priv->crosshair_gc = hid_draw_make_gc (&ghid_graphics);
791 priv->time_since_expose = g_timer_new ();
793 gtk_gl_init(argc, argv);
795 /* setup GL-context */
796 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA |
797 GDK_GL_MODE_STENCIL |
798 GDK_GL_MODE_DOUBLE);
799 if (!priv->glconfig)
801 printf ("Could not setup GL-context!\n");
802 return; /* Should we abort? */
805 /* Setup HID function pointers specific to the GL renderer*/
806 ghid_graphics_class.end_layer = ghid_end_layer;
807 ghid_graphics_class.fill_pcb_polygon = ghid_fill_pcb_polygon;
808 ghid_graphics_class.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;
811 void
812 ghid_shutdown_renderer (GHidPort *port)
814 render_priv *priv = port->render_priv;
816 hid_draw_destroy_gc (priv->crosshair_gc);
817 ghid_cancel_lead_user ();
818 g_free (port->render_priv);
819 port->render_priv = NULL;
822 void
823 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port)
825 render_priv *priv = port->render_priv;
827 gtk_widget_set_gl_capability (widget,
828 priv->glconfig,
829 NULL,
830 TRUE,
831 GDK_GL_RGBA_TYPE);
834 void
835 ghid_drawing_area_configure_hook (GHidPort *port)
839 gboolean
840 ghid_start_drawing (GHidPort *port, GtkWidget *widget)
842 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
843 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
845 /* make GL-context "current" */
846 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
847 return FALSE;
849 port->render_priv->in_context = true;
851 return TRUE;
854 void
855 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
857 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
859 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
860 gdk_gl_drawable_swap_buffers (pGlDrawable);
861 else
862 glFlush ();
864 port->render_priv->in_context = false;
866 /* end drawing to current GL-context */
867 gdk_gl_drawable_gl_end (pGlDrawable);
870 void
871 ghid_screen_update (void)
875 #define Z_NEAR 3.0
876 gboolean
877 ghid_drawing_area_expose_cb (GtkWidget *widget,
878 GdkEventExpose *ev,
879 GHidPort *port)
881 render_priv *priv = port->render_priv;
882 GtkAllocation allocation;
883 BoxType region;
884 Coord min_x, min_y;
885 Coord max_x, max_y;
886 Coord new_x, new_y;
887 Coord min_depth;
888 Coord max_depth;
890 gtk_widget_get_allocation (widget, &allocation);
892 ghid_start_drawing (port, widget);
893 hidgl_start_render ();
895 /* If we don't have any stencil bits available,
896 we can't use the hidgl polygon drawing routine */
897 /* TODO: We could use the GLU tessellator though */
898 if (hidgl_stencil_bits() == 0)
899 ghid_graphics_class.fill_pcb_polygon = common_fill_pcb_polygon;
901 glEnable (GL_BLEND);
902 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
904 glViewport (0, 0, allocation.width, allocation.height);
906 glEnable (GL_SCISSOR_TEST);
907 glScissor (ev->area.x,
908 allocation.height - ev->area.height - ev->area.y,
909 ev->area.width, ev->area.height);
911 glMatrixMode (GL_PROJECTION);
912 glLoadIdentity ();
913 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
914 glMatrixMode (GL_MODELVIEW);
915 glLoadIdentity ();
916 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
917 glMultMatrixf ((GLfloat *)view_matrix);
918 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
919 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
920 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
921 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
922 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
923 -port->view.x0,
924 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
925 -port->view.y0, 0);
926 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
928 glEnable (GL_STENCIL_TEST);
929 glClearColor (port->offlimits_color.red / 65535.,
930 port->offlimits_color.green / 65535.,
931 port->offlimits_color.blue / 65535.,
932 1.);
933 glStencilMask (~0);
934 glClearStencil (0);
935 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
936 hidgl_reset_stencil_usage ();
938 /* Disable the stencil test until we need it - otherwise it gets dirty */
939 glDisable (GL_STENCIL_TEST);
940 glStencilMask (0);
941 glStencilFunc (GL_ALWAYS, 0, 0);
943 /* Test the 8 corners of a cube spanning the event */
944 min_depth = -50; /* FIXME */
945 max_depth = 0; /* FIXME */
947 ghid_unproject_to_z_plane (ev->area.x,
948 ev->area.y,
949 min_depth, &new_x, &new_y);
950 max_x = min_x = new_x;
951 max_y = min_y = new_y;
953 ghid_unproject_to_z_plane (ev->area.x,
954 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,
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, ev->area.y,
967 max_depth, &new_x, &new_y);
968 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
969 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
971 /* */
972 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
973 ev->area.y + ev->area.height,
974 min_depth, &new_x, &new_y);
975 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
976 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
978 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
979 ev->area.y + ev->area.height,
980 max_depth, &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 /* */
985 ghid_unproject_to_z_plane (ev->area.x,
986 ev->area.y + ev->area.height,
987 min_depth,
988 &new_x, &new_y);
989 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
990 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
992 ghid_unproject_to_z_plane (ev->area.x,
993 ev->area.y + ev->area.height,
994 max_depth,
995 &new_x, &new_y);
996 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
997 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
999 region.X1 = min_x; region.X2 = max_x + 1;
1000 region.Y1 = min_y; region.Y2 = max_y + 1;
1002 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1003 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1004 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1005 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1007 glColor3f (port->bg_color.red / 65535.,
1008 port->bg_color.green / 65535.,
1009 port->bg_color.blue / 65535.);
1011 glBegin (GL_QUADS);
1012 glVertex3i (0, 0, -50);
1013 glVertex3i (PCB->MaxWidth, 0, -50);
1014 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
1015 glVertex3i (0, PCB->MaxHeight, -50);
1016 glEnd ();
1018 ghid_draw_bg_image ();
1020 ghid_invalidate_current_gc ();
1021 hid_expose_callback (&ghid_hid, &region, 0);
1022 hidgl_flush_triangles (&buffer);
1024 ghid_draw_grid (&region);
1026 ghid_invalidate_current_gc ();
1028 DrawAttached (priv->crosshair_gc);
1029 DrawMark (priv->crosshair_gc);
1030 hidgl_flush_triangles (&buffer);
1032 draw_crosshair (priv);
1033 hidgl_flush_triangles (&buffer);
1035 draw_lead_user (priv);
1037 hidgl_finish_render ();
1038 ghid_end_drawing (port, widget);
1040 g_timer_start (priv->time_since_expose);
1042 return FALSE;
1045 /* This realize callback is used to work around a crash bug in some mesa
1046 * versions (observed on a machine running the intel i965 driver. It isn't
1047 * obvious why it helps, but somehow fiddling with the GL context here solves
1048 * the issue. The problem appears to have been fixed in recent mesa versions.
1050 void
1051 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1053 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1054 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1056 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1057 return;
1059 gdk_gl_drawable_gl_end (gldrawable);
1060 return;
1063 gboolean
1064 ghid_pinout_preview_expose (GtkWidget *widget,
1065 GdkEventExpose *ev)
1067 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
1068 GtkAllocation allocation;
1069 view_data save_view;
1070 int save_width, save_height;
1071 Coord save_max_width;
1072 Coord save_max_height;
1073 double xz, yz;
1075 save_view = gport->view;
1076 save_width = gport->width;
1077 save_height = gport->height;
1078 save_max_width = PCB->MaxWidth;
1079 save_max_height = PCB->MaxHeight;
1081 /* Setup zoom factor for drawing routines */
1083 gtk_widget_get_allocation (widget, &allocation);
1084 xz = (double) pinout->x_max / allocation.width;
1085 yz = (double) pinout->y_max / allocation.height;
1086 if (xz > yz)
1087 gport->view.coord_per_px = xz;
1088 else
1089 gport->view.coord_per_px = yz;
1091 gport->width = allocation.width;
1092 gport->height = allocation.height;
1093 gport->view.width = allocation.width * gport->view.coord_per_px;
1094 gport->view.height = allocation.height * gport->view.coord_per_px;
1095 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
1096 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
1097 PCB->MaxWidth = pinout->x_max;
1098 PCB->MaxHeight = pinout->y_max;
1100 ghid_start_drawing (gport, widget);
1101 hidgl_start_render ();
1103 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
1104 * call set_layer() as appropriate for us to sub-composite rendering
1105 * from each layer when drawing a single element. If we leave alpha-
1106 * blending on, it means text and overlapping pads are rendered ugly.
1109 glEnable (GL_BLEND);
1110 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1111 #endif
1113 glViewport (0, 0, allocation.width, allocation.height);
1115 #if 0 /* We disable the scissor test here, as it is interacting badly with
1116 * being handed expose events which don't cover the whole window.
1117 * As we have a double-buffered GL window, we end up with unintialised
1118 * contents remaining in the unpainted areas (outside the scissor
1119 * region), and these are being flipped onto the screen.
1121 * The debugging code below shows multiple expose events when the
1122 * window is shown the first time, some of which are very small.
1124 * XXX: There is clearly a perforamnce issue here, in that we may
1125 * be rendering the preview more times, and over a larger area
1126 * than is really required.
1129 glEnable (GL_SCISSOR_TEST);
1130 glScissor (ev->area.x,
1131 allocation.height - ev->area.height - ev->area.y,
1132 ev->area.width, ev->area.height);
1133 #endif
1135 #ifdef DEBUG
1136 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
1137 ev->area.x, ev->area.y, ev->area.width, ev->area.height,
1138 (double)ev->area.x,
1139 (double)(allocation.height - ev->area.height - ev->area.y),
1140 (double)ev->area.width,
1141 (double)ev->area.height);
1142 #endif
1144 glMatrixMode (GL_PROJECTION);
1145 glLoadIdentity ();
1146 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1147 glMatrixMode (GL_MODELVIEW);
1148 glLoadIdentity ();
1149 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1151 glClearColor (gport->bg_color.red / 65535.,
1152 gport->bg_color.green / 65535.,
1153 gport->bg_color.blue / 65535.,
1154 1.);
1155 glStencilMask (~0);
1156 glClearStencil (0);
1157 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1158 hidgl_reset_stencil_usage ();
1160 /* Disable the stencil test until we need it - otherwise it gets dirty */
1161 glDisable (GL_STENCIL_TEST);
1162 glStencilMask (0);
1163 glStencilFunc (GL_ALWAYS, 0, 0);
1165 /* call the drawing routine */
1166 ghid_invalidate_current_gc ();
1167 glPushMatrix ();
1168 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1169 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1170 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1171 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1172 -gport->view.x0,
1173 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1174 -gport->view.y0, 0);
1176 hid_expose_callback (&ghid_hid, NULL, pinout->element);
1177 hidgl_flush_triangles (&buffer);
1178 glPopMatrix ();
1180 hidgl_finish_render ();
1181 ghid_end_drawing (gport, widget);
1183 gport->view = save_view;
1184 gport->width = save_width;
1185 gport->height = save_height;
1186 PCB->MaxWidth = save_max_width;
1187 PCB->MaxHeight = save_max_height;
1189 return FALSE;
1193 GdkPixmap *
1194 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
1196 GdkGLConfig *glconfig;
1197 GdkPixmap *pixmap;
1198 GdkGLPixmap *glpixmap;
1199 GdkGLContext* glcontext;
1200 GdkGLDrawable* gldrawable;
1201 view_data save_view;
1202 int save_width, save_height;
1203 BoxType region;
1205 save_view = gport->view;
1206 save_width = gport->width;
1207 save_height = gport->height;
1209 /* Setup rendering context for drawing routines
1212 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
1213 GDK_GL_MODE_STENCIL |
1214 GDK_GL_MODE_SINGLE);
1216 pixmap = gdk_pixmap_new (NULL, width, height, depth);
1217 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
1218 gldrawable = GDK_GL_DRAWABLE (glpixmap);
1219 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
1221 /* Setup zoom factor for drawing routines */
1223 gport->view.coord_per_px = zoom;
1224 gport->width = width;
1225 gport->height = height;
1226 gport->view.width = width * gport->view.coord_per_px;
1227 gport->view.height = height * gport->view.coord_per_px;
1228 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
1229 gport->view.x0 -= gport->view.height / 2;
1230 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
1231 gport->view.y0 -= gport->view.width / 2;
1233 /* make GL-context "current" */
1234 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
1235 return NULL;
1237 hidgl_start_render ();
1238 gport->render_priv->in_context = true;
1240 glEnable (GL_BLEND);
1241 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1243 glViewport (0, 0, width, height);
1245 glEnable (GL_SCISSOR_TEST);
1246 glScissor (0, 0, width, height);
1248 glMatrixMode (GL_PROJECTION);
1249 glLoadIdentity ();
1250 glOrtho (0, width, height, 0, -100000, 100000);
1251 glMatrixMode (GL_MODELVIEW);
1252 glLoadIdentity ();
1253 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1255 glClearColor (gport->bg_color.red / 65535.,
1256 gport->bg_color.green / 65535.,
1257 gport->bg_color.blue / 65535.,
1258 1.);
1259 glStencilMask (~0);
1260 glClearStencil (0);
1261 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1262 hidgl_reset_stencil_usage ();
1264 /* Disable the stencil test until we need it - otherwise it gets dirty */
1265 glDisable (GL_STENCIL_TEST);
1266 glStencilMask (0);
1267 glStencilFunc (GL_ALWAYS, 0, 0);
1269 /* call the drawing routine */
1270 ghid_invalidate_current_gc ();
1271 glPushMatrix ();
1272 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1273 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1274 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1275 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1276 -gport->view.x0,
1277 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1278 -gport->view.y0, 0);
1280 region.X1 = MIN(Px(0), Px(gport->width + 1));
1281 region.Y1 = MIN(Py(0), Py(gport->height + 1));
1282 region.X2 = MAX(Px(0), Px(gport->width + 1));
1283 region.Y2 = MAX(Py(0), Py(gport->height + 1));
1285 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1286 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1287 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1288 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1290 hid_expose_callback (&ghid_hid, &region, NULL);
1291 hidgl_flush_triangles (&buffer);
1292 glPopMatrix ();
1294 glFlush ();
1296 hidgl_finish_render ();
1298 /* end drawing to current GL-context */
1299 gport->render_priv->in_context = false;
1300 gdk_gl_drawable_gl_end (gldrawable);
1302 gdk_pixmap_unset_gl_capability (pixmap);
1304 g_object_unref (glconfig);
1305 g_object_unref (glcontext);
1307 gport->view = save_view;
1308 gport->width = save_width;
1309 gport->height = save_height;
1311 return pixmap;
1314 HID_DRAW *
1315 ghid_request_debug_draw (void)
1317 GHidPort *port = gport;
1318 GtkWidget *widget = port->drawing_area;
1319 GtkAllocation allocation;
1321 gtk_widget_get_allocation (widget, &allocation);
1323 ghid_start_drawing (port, widget);
1324 hidgl_start_render ();
1326 glViewport (0, 0, allocation.width, allocation.height);
1328 glMatrixMode (GL_PROJECTION);
1329 glLoadIdentity ();
1330 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
1331 glMatrixMode (GL_MODELVIEW);
1332 glLoadIdentity ();
1333 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1335 ghid_invalidate_current_gc ();
1337 /* Setup stenciling */
1338 glDisable (GL_STENCIL_TEST);
1340 glPushMatrix ();
1341 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1342 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1343 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1344 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1345 -port->view.x0,
1346 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1347 -port->view.y0, 0);
1349 return ghid_hid.graphics;
1352 void
1353 ghid_flush_debug_draw (void)
1355 GtkWidget *widget = gport->drawing_area;
1356 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1358 hidgl_flush_triangles (&buffer);
1360 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1361 gdk_gl_drawable_swap_buffers (pGlDrawable);
1362 else
1363 glFlush ();
1366 void
1367 ghid_finish_debug_draw (void)
1369 hidgl_flush_triangles (&buffer);
1370 glPopMatrix ();
1372 hidgl_finish_render ();
1373 ghid_end_drawing (gport, gport->drawing_area);
1376 static float
1377 determinant_2x2 (float m[2][2])
1379 float det;
1380 det = m[0][0] * m[1][1] -
1381 m[0][1] * m[1][0];
1382 return det;
1385 #if 0
1386 static float
1387 determinant_4x4 (float m[4][4])
1389 float det;
1390 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] -
1391 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
1392 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
1393 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
1394 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
1395 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
1396 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
1397 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
1398 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
1399 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
1400 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
1401 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
1402 return det;
1404 #endif
1406 static void
1407 invert_2x2 (float m[2][2], float out[2][2])
1409 float scale = 1 / determinant_2x2 (m);
1410 out[0][0] = m[1][1] * scale;
1411 out[0][1] = -m[0][1] * scale;
1412 out[1][0] = -m[1][0] * scale;
1413 out[1][1] = m[0][0] * scale;
1416 #if 0
1417 static void
1418 invert_4x4 (float m[4][4], float out[4][4])
1420 float scale = 1 / determinant_4x4 (m);
1422 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
1423 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
1424 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
1425 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
1426 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
1427 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
1428 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
1429 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
1430 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
1431 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
1432 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
1433 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
1434 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
1435 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
1436 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
1437 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
1438 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
1439 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
1440 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
1441 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
1442 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
1443 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
1444 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
1445 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
1446 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
1447 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
1448 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
1449 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
1450 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
1451 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
1452 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
1453 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
1454 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
1455 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
1456 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
1457 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
1458 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
1459 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
1460 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
1461 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
1462 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
1463 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
1464 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
1465 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
1466 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
1467 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
1468 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
1469 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
1471 #endif
1474 static void
1475 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
1477 float mat[2][2];
1478 float inv_mat[2][2];
1479 float x, y;
1482 ex = view_matrix[0][0] * vx +
1483 view_matrix[0][1] * vy +
1484 view_matrix[0][2] * vz +
1485 view_matrix[0][3] * 1;
1486 ey = view_matrix[1][0] * vx +
1487 view_matrix[1][1] * vy +
1488 view_matrix[1][2] * vz +
1489 view_matrix[1][3] * 1;
1490 UNKNOWN ez = view_matrix[2][0] * vx +
1491 view_matrix[2][1] * vy +
1492 view_matrix[2][2] * vz +
1493 view_matrix[2][3] * 1;
1495 ex - view_matrix[0][3] * 1
1496 - view_matrix[0][2] * vz
1497 = view_matrix[0][0] * vx +
1498 view_matrix[0][1] * vy;
1500 ey - view_matrix[1][3] * 1
1501 - view_matrix[1][2] * vz
1502 = view_matrix[1][0] * vx +
1503 view_matrix[1][1] * vy;
1506 /* NB: last_modelview_matrix is transposed in memory! */
1507 x = (float)ex - last_modelview_matrix[3][0] * 1
1508 - last_modelview_matrix[2][0] * pcb_z;
1510 y = (float)ey - last_modelview_matrix[3][1] * 1
1511 - last_modelview_matrix[2][1] * pcb_z;
1514 x = view_matrix[0][0] * vx +
1515 view_matrix[0][1] * vy;
1517 y = view_matrix[1][0] * vx +
1518 view_matrix[1][1] * vy;
1520 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1521 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1524 mat[0][0] = last_modelview_matrix[0][0];
1525 mat[0][1] = last_modelview_matrix[1][0];
1526 mat[1][0] = last_modelview_matrix[0][1];
1527 mat[1][1] = last_modelview_matrix[1][1];
1529 /* if (determinant_2x2 (mat) < 0.00001) */
1530 /* printf ("Determinant is quite small\n"); */
1532 invert_2x2 (mat, inv_mat);
1534 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
1535 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
1539 bool
1540 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
1542 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
1544 return true;
1547 bool
1548 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
1550 /* NB: last_modelview_matrix is transposed in memory */
1551 float w = last_modelview_matrix[0][3] * (float)pcb_x +
1552 last_modelview_matrix[1][3] * (float)pcb_y +
1553 last_modelview_matrix[2][3] * 0. +
1554 last_modelview_matrix[3][3] * 1.;
1556 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
1557 last_modelview_matrix[1][0] * (float)pcb_y +
1558 last_modelview_matrix[2][0] * 0. +
1559 last_modelview_matrix[3][0] * 1.) / w;
1560 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
1561 last_modelview_matrix[1][1] * (float)pcb_y +
1562 last_modelview_matrix[2][1] * 0. +
1563 last_modelview_matrix[3][1] * 1.) / w;
1565 return true;
1568 void
1569 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
1571 global_view_2d = view_2d;
1572 ghid_invalidate_all ();
1575 void
1576 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
1578 #ifdef DEBUG_ROTATE
1579 int row, column;
1580 #endif
1582 build_rotmatrix (view_matrix, quarternion);
1584 #ifdef DEBUG_ROTATE
1585 for (row = 0; row < 4; row++) {
1586 printf ("[ %f", view_matrix[row][0]);
1587 for (column = 1; column < 4; column++) {
1588 printf (",\t%f", view_matrix[row][column]);
1590 printf ("\t]\n");
1592 printf ("\n");
1593 #endif
1595 ghid_invalidate_all ();
1599 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1600 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1601 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1602 #define LEAD_USER_ARC_COUNT 3
1603 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1604 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1605 #define LEAD_USER_COLOR_R 1.
1606 #define LEAD_USER_COLOR_G 1.
1607 #define LEAD_USER_COLOR_B 0.
1609 static void
1610 draw_lead_user (render_priv *priv)
1612 int i;
1613 double radius = priv->lead_user_radius;
1614 double width = MM_TO_COORD (LEAD_USER_WIDTH);
1615 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
1617 if (!priv->lead_user)
1618 return;
1620 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
1621 glEnable (GL_COLOR_LOGIC_OP);
1622 glLogicOp (GL_XOR);
1623 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
1626 /* arcs at the approrpriate radii */
1628 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
1630 if (radius < width)
1631 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1633 /* Draw an arc at radius */
1634 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
1635 radius, radius, 0, 360, gport->view.coord_per_px);
1638 hidgl_flush_triangles (&buffer);
1639 glPopAttrib ();
1642 gboolean
1643 lead_user_cb (gpointer data)
1645 render_priv *priv = data;
1646 Coord step;
1647 double elapsed_time;
1649 /* Queue a redraw */
1650 ghid_invalidate_all ();
1652 /* Update radius */
1653 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
1654 g_timer_start (priv->lead_user_timer);
1656 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
1657 if (priv->lead_user_radius > step)
1658 priv->lead_user_radius -= step;
1659 else
1660 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1662 return TRUE;
1665 void
1666 ghid_lead_user_to_location (Coord x, Coord y)
1668 render_priv *priv = gport->render_priv;
1670 ghid_cancel_lead_user ();
1672 priv->lead_user = true;
1673 priv->lead_user_x = x;
1674 priv->lead_user_y = y;
1675 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1676 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
1677 priv->lead_user_timer = g_timer_new ();
1680 void
1681 ghid_cancel_lead_user (void)
1683 render_priv *priv = gport->render_priv;
1685 if (priv->lead_user_timeout)
1686 g_source_remove (priv->lead_user_timeout);
1688 if (priv->lead_user_timer)
1689 g_timer_destroy (priv->lead_user_timer);
1691 if (priv->lead_user)
1692 ghid_invalidate_all ();
1694 priv->lead_user_timeout = 0;
1695 priv->lead_user_timer = NULL;
1696 priv->lead_user = false;