find.c: Use SetThing, rather than open-coding assignments to thing_*
[geda-pcb/pcjc2.git] / src / hid / gtk / gtkhid-gl.c
blobac695e8a5d9b552c38bcf8777531b3e2c48ada30
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 gui->graphics->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, GtkWidget *widget)
825 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget);
826 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
828 /* make GL-context "current" */
829 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext))
830 return FALSE;
832 port->render_priv->in_context = true;
834 return TRUE;
837 void
838 ghid_end_drawing (GHidPort *port, GtkWidget *widget)
840 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
842 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
843 gdk_gl_drawable_swap_buffers (pGlDrawable);
844 else
845 glFlush ();
847 port->render_priv->in_context = false;
849 /* end drawing to current GL-context */
850 gdk_gl_drawable_gl_end (pGlDrawable);
853 void
854 ghid_screen_update (void)
858 #define Z_NEAR 3.0
859 gboolean
860 ghid_drawing_area_expose_cb (GtkWidget *widget,
861 GdkEventExpose *ev,
862 GHidPort *port)
864 render_priv *priv = port->render_priv;
865 GtkAllocation allocation;
866 BoxType region;
867 Coord min_x, min_y;
868 Coord max_x, max_y;
869 Coord new_x, new_y;
870 Coord min_depth;
871 Coord max_depth;
873 gtk_widget_get_allocation (widget, &allocation);
875 ghid_start_drawing (port, widget);
876 hidgl_start_render ();
878 /* If we don't have any stencil bits available,
879 we can't use the hidgl polygon drawing routine */
880 /* TODO: We could use the GLU tessellator though */
881 if (hidgl_stencil_bits() == 0)
882 ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon;
884 glEnable (GL_BLEND);
885 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
887 glViewport (0, 0, allocation.width, allocation.height);
889 glEnable (GL_SCISSOR_TEST);
890 glScissor (ev->area.x,
891 allocation.height - ev->area.height - ev->area.y,
892 ev->area.width, ev->area.height);
894 glMatrixMode (GL_PROJECTION);
895 glLoadIdentity ();
896 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
897 glMatrixMode (GL_MODELVIEW);
898 glLoadIdentity ();
899 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0);
900 glMultMatrixf ((GLfloat *)view_matrix);
901 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0);
902 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
903 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
904 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px);
905 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
906 -port->view.x0,
907 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
908 -port->view.y0, 0);
909 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix);
911 glEnable (GL_STENCIL_TEST);
912 glClearColor (port->offlimits_color.red / 65535.,
913 port->offlimits_color.green / 65535.,
914 port->offlimits_color.blue / 65535.,
915 1.);
916 glStencilMask (~0);
917 glClearStencil (0);
918 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
919 hidgl_reset_stencil_usage ();
921 /* Disable the stencil test until we need it - otherwise it gets dirty */
922 glDisable (GL_STENCIL_TEST);
923 glStencilMask (0);
924 glStencilFunc (GL_ALWAYS, 0, 0);
926 /* Test the 8 corners of a cube spanning the event */
927 min_depth = -50; /* FIXME */
928 max_depth = 0; /* FIXME */
930 ghid_unproject_to_z_plane (ev->area.x,
931 ev->area.y,
932 min_depth, &new_x, &new_y);
933 max_x = min_x = new_x;
934 max_y = min_y = new_y;
936 ghid_unproject_to_z_plane (ev->area.x,
937 ev->area.y,
938 max_depth, &new_x, &new_y);
939 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
940 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
942 /* */
943 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
944 ev->area.y,
945 min_depth, &new_x, &new_y);
946 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
947 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
949 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y,
950 max_depth, &new_x, &new_y);
951 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
952 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
954 /* */
955 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
956 ev->area.y + ev->area.height,
957 min_depth, &new_x, &new_y);
958 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
959 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
961 ghid_unproject_to_z_plane (ev->area.x + ev->area.width,
962 ev->area.y + ev->area.height,
963 max_depth, &new_x, &new_y);
964 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
965 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
967 /* */
968 ghid_unproject_to_z_plane (ev->area.x,
969 ev->area.y + ev->area.height,
970 min_depth,
971 &new_x, &new_y);
972 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
973 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
975 ghid_unproject_to_z_plane (ev->area.x,
976 ev->area.y + ev->area.height,
977 max_depth,
978 &new_x, &new_y);
979 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x);
980 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y);
982 region.X1 = min_x; region.X2 = max_x + 1;
983 region.Y1 = min_y; region.Y2 = max_y + 1;
985 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
986 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
987 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
988 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
990 glColor3f (port->bg_color.red / 65535.,
991 port->bg_color.green / 65535.,
992 port->bg_color.blue / 65535.);
994 glBegin (GL_QUADS);
995 glVertex3i (0, 0, -50);
996 glVertex3i (PCB->MaxWidth, 0, -50);
997 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50);
998 glVertex3i (0, PCB->MaxHeight, -50);
999 glEnd ();
1001 ghid_draw_bg_image ();
1003 ghid_invalidate_current_gc ();
1004 hid_expose_callback (&ghid_hid, &region, 0);
1005 hidgl_flush_triangles (&buffer);
1007 ghid_draw_grid (&region);
1009 ghid_invalidate_current_gc ();
1011 DrawAttached ();
1012 DrawMark ();
1013 hidgl_flush_triangles (&buffer);
1015 draw_crosshair (priv);
1016 hidgl_flush_triangles (&buffer);
1018 draw_lead_user (priv);
1020 hidgl_finish_render ();
1021 ghid_end_drawing (port, widget);
1023 g_timer_start (priv->time_since_expose);
1025 return FALSE;
1028 /* This realize callback is used to work around a crash bug in some mesa
1029 * versions (observed on a machine running the intel i965 driver. It isn't
1030 * obvious why it helps, but somehow fiddling with the GL context here solves
1031 * the issue. The problem appears to have been fixed in recent mesa versions.
1033 void
1034 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data)
1036 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
1037 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
1039 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
1040 return;
1042 gdk_gl_drawable_gl_end (gldrawable);
1043 return;
1046 gboolean
1047 ghid_pinout_preview_expose (GtkWidget *widget,
1048 GdkEventExpose *ev)
1050 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget);
1051 GtkAllocation allocation;
1052 view_data save_view;
1053 int save_width, save_height;
1054 Coord save_max_width;
1055 Coord save_max_height;
1056 double xz, yz;
1058 save_view = gport->view;
1059 save_width = gport->width;
1060 save_height = gport->height;
1061 save_max_width = PCB->MaxWidth;
1062 save_max_height = PCB->MaxHeight;
1064 /* Setup zoom factor for drawing routines */
1066 gtk_widget_get_allocation (widget, &allocation);
1067 xz = (double) pinout->x_max / allocation.width;
1068 yz = (double) pinout->y_max / allocation.height;
1069 if (xz > yz)
1070 gport->view.coord_per_px = xz;
1071 else
1072 gport->view.coord_per_px = yz;
1074 gport->width = allocation.width;
1075 gport->height = allocation.height;
1076 gport->view.width = allocation.width * gport->view.coord_per_px;
1077 gport->view.height = allocation.height * gport->view.coord_per_px;
1078 gport->view.x0 = (pinout->x_max - gport->view.width) / 2;
1079 gport->view.y0 = (pinout->y_max - gport->view.height) / 2;
1080 PCB->MaxWidth = pinout->x_max;
1081 PCB->MaxHeight = pinout->y_max;
1083 ghid_start_drawing (gport, widget);
1084 hidgl_start_render ();
1086 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
1087 * call set_layer() as appropriate for us to sub-composite rendering
1088 * from each layer when drawing a single element. If we leave alpha-
1089 * blending on, it means text and overlapping pads are rendered ugly.
1092 glEnable (GL_BLEND);
1093 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1094 #endif
1096 glViewport (0, 0, allocation.width, allocation.height);
1098 #if 0 /* We disable the scissor test here, as it is interacting badly with
1099 * being handed expose events which don't cover the whole window.
1100 * As we have a double-buffered GL window, we end up with unintialised
1101 * contents remaining in the unpainted areas (outside the scissor
1102 * region), and these are being flipped onto the screen.
1104 * The debugging code below shows multiple expose events when the
1105 * window is shown the first time, some of which are very small.
1107 * XXX: There is clearly a perforamnce issue here, in that we may
1108 * be rendering the preview more times, and over a larger area
1109 * than is really required.
1112 glEnable (GL_SCISSOR_TEST);
1113 glScissor (ev->area.x,
1114 allocation.height - ev->area.height - ev->area.y,
1115 ev->area.width, ev->area.height);
1116 #endif
1118 #ifdef DEBUG
1119 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
1120 ev->area.x, ev->area.y, ev->area.width, ev->area.height,
1121 (double)ev->area.x,
1122 (double)(allocation.height - ev->area.height - ev->area.y),
1123 (double)ev->area.width,
1124 (double)ev->area.height);
1125 #endif
1127 glMatrixMode (GL_PROJECTION);
1128 glLoadIdentity ();
1129 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000);
1130 glMatrixMode (GL_MODELVIEW);
1131 glLoadIdentity ();
1132 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1134 glClearColor (gport->bg_color.red / 65535.,
1135 gport->bg_color.green / 65535.,
1136 gport->bg_color.blue / 65535.,
1137 1.);
1138 glStencilMask (~0);
1139 glClearStencil (0);
1140 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1141 hidgl_reset_stencil_usage ();
1143 /* Disable the stencil test until we need it - otherwise it gets dirty */
1144 glDisable (GL_STENCIL_TEST);
1145 glStencilMask (0);
1146 glStencilFunc (GL_ALWAYS, 0, 0);
1148 /* call the drawing routine */
1149 ghid_invalidate_current_gc ();
1150 glPushMatrix ();
1151 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1152 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1153 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1154 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1155 -gport->view.x0,
1156 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1157 -gport->view.y0, 0);
1159 hid_expose_callback (&ghid_hid, NULL, pinout->element);
1160 hidgl_flush_triangles (&buffer);
1161 glPopMatrix ();
1163 hidgl_finish_render ();
1164 ghid_end_drawing (gport, widget);
1166 gport->view = save_view;
1167 gport->width = save_width;
1168 gport->height = save_height;
1169 PCB->MaxWidth = save_max_width;
1170 PCB->MaxHeight = save_max_height;
1172 return FALSE;
1176 GdkPixmap *
1177 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth)
1179 GdkGLConfig *glconfig;
1180 GdkPixmap *pixmap;
1181 GdkGLPixmap *glpixmap;
1182 GdkGLContext* glcontext;
1183 GdkGLDrawable* gldrawable;
1184 view_data save_view;
1185 int save_width, save_height;
1186 BoxType region;
1188 save_view = gport->view;
1189 save_width = gport->width;
1190 save_height = gport->height;
1192 /* Setup rendering context for drawing routines
1195 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
1196 GDK_GL_MODE_STENCIL |
1197 GDK_GL_MODE_SINGLE);
1199 pixmap = gdk_pixmap_new (NULL, width, height, depth);
1200 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL);
1201 gldrawable = GDK_GL_DRAWABLE (glpixmap);
1202 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE);
1204 /* Setup zoom factor for drawing routines */
1206 gport->view.coord_per_px = zoom;
1207 gport->width = width;
1208 gport->height = height;
1209 gport->view.width = width * gport->view.coord_per_px;
1210 gport->view.height = height * gport->view.coord_per_px;
1211 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx;
1212 gport->view.x0 -= gport->view.height / 2;
1213 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy;
1214 gport->view.y0 -= gport->view.width / 2;
1216 /* make GL-context "current" */
1217 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) {
1218 return NULL;
1220 hidgl_start_render ();
1221 gport->render_priv->in_context = true;
1223 glEnable (GL_BLEND);
1224 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1226 glViewport (0, 0, width, height);
1228 glEnable (GL_SCISSOR_TEST);
1229 glScissor (0, 0, width, height);
1231 glMatrixMode (GL_PROJECTION);
1232 glLoadIdentity ();
1233 glOrtho (0, width, height, 0, -100000, 100000);
1234 glMatrixMode (GL_MODELVIEW);
1235 glLoadIdentity ();
1236 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1238 glClearColor (gport->bg_color.red / 65535.,
1239 gport->bg_color.green / 65535.,
1240 gport->bg_color.blue / 65535.,
1241 1.);
1242 glStencilMask (~0);
1243 glClearStencil (0);
1244 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1245 hidgl_reset_stencil_usage ();
1247 /* Disable the stencil test until we need it - otherwise it gets dirty */
1248 glDisable (GL_STENCIL_TEST);
1249 glStencilMask (0);
1250 glStencilFunc (GL_ALWAYS, 0, 0);
1252 /* call the drawing routine */
1253 ghid_invalidate_current_gc ();
1254 glPushMatrix ();
1255 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px,
1256 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px,
1257 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1258 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth :
1259 -gport->view.x0,
1260 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight :
1261 -gport->view.y0, 0);
1263 region.X1 = MIN(Px(0), Px(gport->width + 1));
1264 region.Y1 = MIN(Py(0), Py(gport->height + 1));
1265 region.X2 = MAX(Px(0), Px(gport->width + 1));
1266 region.Y2 = MAX(Py(0), Py(gport->height + 1));
1268 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1));
1269 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2));
1270 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1));
1271 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2));
1273 hid_expose_callback (&ghid_hid, &region, NULL);
1274 hidgl_flush_triangles (&buffer);
1275 glPopMatrix ();
1277 glFlush ();
1279 hidgl_finish_render ();
1281 /* end drawing to current GL-context */
1282 gport->render_priv->in_context = false;
1283 gdk_gl_drawable_gl_end (gldrawable);
1285 gdk_pixmap_unset_gl_capability (pixmap);
1287 g_object_unref (glconfig);
1288 g_object_unref (glcontext);
1290 gport->view = save_view;
1291 gport->width = save_width;
1292 gport->height = save_height;
1294 return pixmap;
1297 HID *
1298 ghid_request_debug_draw (void)
1300 GHidPort *port = gport;
1301 GtkWidget *widget = port->drawing_area;
1302 GtkAllocation allocation;
1304 gtk_widget_get_allocation (widget, &allocation);
1306 ghid_start_drawing (port, widget);
1307 hidgl_start_render ();
1309 glViewport (0, 0, allocation.width, allocation.height);
1311 glMatrixMode (GL_PROJECTION);
1312 glLoadIdentity ();
1313 glOrtho (0, allocation.width, allocation.height, 0, 0, 100);
1314 glMatrixMode (GL_MODELVIEW);
1315 glLoadIdentity ();
1316 glTranslatef (0.0f, 0.0f, -Z_NEAR);
1318 ghid_invalidate_current_gc ();
1320 /* Setup stenciling */
1321 glDisable (GL_STENCIL_TEST);
1323 glPushMatrix ();
1324 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px,
1325 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px,
1326 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px);
1327 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth :
1328 -port->view.x0,
1329 port->view.flip_y ? port->view.y0 - PCB->MaxHeight :
1330 -port->view.y0, 0);
1332 return &ghid_hid;
1335 void
1336 ghid_flush_debug_draw (void)
1338 GtkWidget *widget = gport->drawing_area;
1339 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget);
1341 hidgl_flush_triangles (&buffer);
1343 if (gdk_gl_drawable_is_double_buffered (pGlDrawable))
1344 gdk_gl_drawable_swap_buffers (pGlDrawable);
1345 else
1346 glFlush ();
1349 void
1350 ghid_finish_debug_draw (void)
1352 hidgl_flush_triangles (&buffer);
1353 glPopMatrix ();
1355 hidgl_finish_render ();
1356 ghid_end_drawing (gport, gport->drawing_area);
1359 static float
1360 determinant_2x2 (float m[2][2])
1362 float det;
1363 det = m[0][0] * m[1][1] -
1364 m[0][1] * m[1][0];
1365 return det;
1368 #if 0
1369 static float
1370 determinant_4x4 (float m[4][4])
1372 float det;
1373 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] -
1374 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] +
1375 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] -
1376 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] +
1377 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] -
1378 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] +
1379 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] -
1380 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] +
1381 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] -
1382 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] +
1383 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] -
1384 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3];
1385 return det;
1387 #endif
1389 static void
1390 invert_2x2 (float m[2][2], float out[2][2])
1392 float scale = 1 / determinant_2x2 (m);
1393 out[0][0] = m[1][1] * scale;
1394 out[0][1] = -m[0][1] * scale;
1395 out[1][0] = -m[1][0] * scale;
1396 out[1][1] = m[0][0] * scale;
1399 #if 0
1400 static void
1401 invert_4x4 (float m[4][4], float out[4][4])
1403 float scale = 1 / determinant_4x4 (m);
1405 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] +
1406 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] -
1407 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale;
1408 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] -
1409 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] +
1410 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale;
1411 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] +
1412 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] -
1413 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale;
1414 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] -
1415 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] +
1416 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale;
1417 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] -
1418 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] +
1419 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale;
1420 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] +
1421 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] -
1422 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale;
1423 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] -
1424 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] +
1425 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale;
1426 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] +
1427 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] -
1428 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale;
1429 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] +
1430 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] -
1431 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale;
1432 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] -
1433 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] +
1434 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale;
1435 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] +
1436 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] -
1437 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale;
1438 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] -
1439 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] +
1440 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale;
1441 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] -
1442 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] +
1443 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale;
1444 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] +
1445 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] -
1446 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale;
1447 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] -
1448 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] +
1449 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale;
1450 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] +
1451 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] -
1452 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale;
1454 #endif
1457 static void
1458 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y)
1460 float mat[2][2];
1461 float inv_mat[2][2];
1462 float x, y;
1465 ex = view_matrix[0][0] * vx +
1466 view_matrix[0][1] * vy +
1467 view_matrix[0][2] * vz +
1468 view_matrix[0][3] * 1;
1469 ey = view_matrix[1][0] * vx +
1470 view_matrix[1][1] * vy +
1471 view_matrix[1][2] * vz +
1472 view_matrix[1][3] * 1;
1473 UNKNOWN ez = view_matrix[2][0] * vx +
1474 view_matrix[2][1] * vy +
1475 view_matrix[2][2] * vz +
1476 view_matrix[2][3] * 1;
1478 ex - view_matrix[0][3] * 1
1479 - view_matrix[0][2] * vz
1480 = view_matrix[0][0] * vx +
1481 view_matrix[0][1] * vy;
1483 ey - view_matrix[1][3] * 1
1484 - view_matrix[1][2] * vz
1485 = view_matrix[1][0] * vx +
1486 view_matrix[1][1] * vy;
1489 /* NB: last_modelview_matrix is transposed in memory! */
1490 x = (float)ex - last_modelview_matrix[3][0] * 1
1491 - last_modelview_matrix[2][0] * pcb_z;
1493 y = (float)ey - last_modelview_matrix[3][1] * 1
1494 - last_modelview_matrix[2][1] * pcb_z;
1497 x = view_matrix[0][0] * vx +
1498 view_matrix[0][1] * vy;
1500 y = view_matrix[1][0] * vx +
1501 view_matrix[1][1] * vy;
1503 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1504 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1507 mat[0][0] = last_modelview_matrix[0][0];
1508 mat[0][1] = last_modelview_matrix[1][0];
1509 mat[1][0] = last_modelview_matrix[0][1];
1510 mat[1][1] = last_modelview_matrix[1][1];
1512 /* if (determinant_2x2 (mat) < 0.00001) */
1513 /* printf ("Determinant is quite small\n"); */
1515 invert_2x2 (mat, inv_mat);
1517 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y);
1518 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y);
1522 bool
1523 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y)
1525 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y);
1527 return true;
1530 bool
1531 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y)
1533 /* NB: last_modelview_matrix is transposed in memory */
1534 float w = last_modelview_matrix[0][3] * (float)pcb_x +
1535 last_modelview_matrix[1][3] * (float)pcb_y +
1536 last_modelview_matrix[2][3] * 0. +
1537 last_modelview_matrix[3][3] * 1.;
1539 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x +
1540 last_modelview_matrix[1][0] * (float)pcb_y +
1541 last_modelview_matrix[2][0] * 0. +
1542 last_modelview_matrix[3][0] * 1.) / w;
1543 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x +
1544 last_modelview_matrix[1][1] * (float)pcb_y +
1545 last_modelview_matrix[2][1] * 0. +
1546 last_modelview_matrix[3][1] * 1.) / w;
1548 return true;
1551 void
1552 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata)
1554 global_view_2d = view_2d;
1555 ghid_invalidate_all ();
1558 void
1559 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata)
1561 #ifdef DEBUG_ROTATE
1562 int row, column;
1563 #endif
1565 build_rotmatrix (view_matrix, quarternion);
1567 #ifdef DEBUG_ROTATE
1568 for (row = 0; row < 4; row++) {
1569 printf ("[ %f", view_matrix[row][0]);
1570 for (column = 1; column < 4; column++) {
1571 printf (",\t%f", view_matrix[row][column]);
1573 printf ("\t]\n");
1575 printf ("\n");
1576 #endif
1578 ghid_invalidate_all ();
1582 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1583 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1584 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1585 #define LEAD_USER_ARC_COUNT 3
1586 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1587 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1588 #define LEAD_USER_COLOR_R 1.
1589 #define LEAD_USER_COLOR_G 1.
1590 #define LEAD_USER_COLOR_B 0.
1592 static void
1593 draw_lead_user (render_priv *priv)
1595 int i;
1596 double radius = priv->lead_user_radius;
1597 double width = MM_TO_COORD (LEAD_USER_WIDTH);
1598 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION);
1600 if (!priv->lead_user)
1601 return;
1603 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT);
1604 glEnable (GL_COLOR_LOGIC_OP);
1605 glLogicOp (GL_XOR);
1606 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B);
1609 /* arcs at the approrpriate radii */
1611 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation)
1613 if (radius < width)
1614 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1616 /* Draw an arc at radius */
1617 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y,
1618 radius, radius, 0, 360, gport->view.coord_per_px);
1621 hidgl_flush_triangles (&buffer);
1622 glPopAttrib ();
1625 gboolean
1626 lead_user_cb (gpointer data)
1628 render_priv *priv = data;
1629 Coord step;
1630 double elapsed_time;
1632 /* Queue a redraw */
1633 ghid_invalidate_all ();
1635 /* Update radius */
1636 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL);
1637 g_timer_start (priv->lead_user_timer);
1639 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time);
1640 if (priv->lead_user_radius > step)
1641 priv->lead_user_radius -= step;
1642 else
1643 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1645 return TRUE;
1648 void
1649 ghid_lead_user_to_location (Coord x, Coord y)
1651 render_priv *priv = gport->render_priv;
1653 ghid_cancel_lead_user ();
1655 priv->lead_user = true;
1656 priv->lead_user_x = x;
1657 priv->lead_user_y = y;
1658 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS);
1659 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv);
1660 priv->lead_user_timer = g_timer_new ();
1663 void
1664 ghid_cancel_lead_user (void)
1666 render_priv *priv = gport->render_priv;
1668 if (priv->lead_user_timeout)
1669 g_source_remove (priv->lead_user_timeout);
1671 if (priv->lead_user_timer)
1672 g_timer_destroy (priv->lead_user_timer);
1674 if (priv->lead_user)
1675 ghid_invalidate_all ();
1677 priv->lead_user_timeout = 0;
1678 priv->lead_user_timer = NULL;
1679 priv->lead_user = false;