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/
18 #define GL_GLEXT_PROTOTYPES 1
20 /* This follows autoconf's recommendation for the AX_CHECK_GL macro
21 https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */
22 #if defined HAVE_WINDOWS_H && defined _WIN32
25 #if defined HAVE_GL_GL_H
27 #elif defined HAVE_OPENGL_GL_H
28 # include <OpenGL/gl.h>
30 # error autoconf couldnt find gl.h
33 #include <gtk/gtkgl.h>
34 #include "hid/common/hidgl.h"
36 #include "hid/common/draw_helpers.h"
37 #include "hid/common/trackball.h"
39 #ifdef HAVE_LIBDMALLOC
44 extern HID_DRAW ghid_graphics
;
46 static hidGC current_gc
= NULL
;
48 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window)
50 #define USE_GC(gc) if (!use_gc(gc)) return
52 static enum mask_mode cur_mask
= HID_MASK_OFF
;
53 static GLfloat view_matrix
[4][4] = {{1.0, 0.0, 0.0, 0.0},
56 {0.0, 0.0, 0.0, 1.0}};
57 static GLfloat last_modelview_matrix
[4][4] = {{1.0, 0.0, 0.0, 0.0},
60 {0.0, 0.0, 0.0, 1.0}};
61 static int global_view_2d
= 1;
63 typedef struct render_priv
{
64 GdkGLConfig
*glconfig
;
67 int subcomposite_stencil_bit
;
68 char *current_colorname
;
69 double current_alpha_mult
;
70 GTimer
*time_since_expose
;
72 /* Feature for leading the user to a particular location */
73 guint lead_user_timeout
;
74 GTimer
*lead_user_timer
;
76 Coord lead_user_radius
;
84 typedef struct hid_gc_struct
88 const char *colorname
;
96 static void draw_lead_user (render_priv
*priv
);
97 static void ghid_unproject_to_z_plane (int ex
, int ey
, Coord pcb_z
, Coord
*pcb_x
, Coord
*pcb_y
);
101 start_subcomposite (void)
103 render_priv
*priv
= gport
->render_priv
;
106 /* Flush out any existing geoemtry to be rendered */
107 hidgl_flush_triangles (&buffer
);
109 glEnable (GL_STENCIL_TEST
); /* Enable Stencil test */
110 glStencilOp (GL_KEEP
, GL_KEEP
, GL_REPLACE
); /* Stencil pass => replace stencil value (with 1) */
112 stencil_bit
= hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
113 glStencilMask (stencil_bit
); /* Only write to our subcompositing stencil bitplane */
114 glStencilFunc (GL_GREATER
, stencil_bit
, stencil_bit
); /* Pass stencil test if our assigned bit is clear */
116 priv
->subcomposite_stencil_bit
= stencil_bit
;
120 end_subcomposite (void)
122 render_priv
*priv
= gport
->render_priv
;
124 /* Flush out any existing geoemtry to be rendered */
125 hidgl_flush_triangles (&buffer
);
127 hidgl_return_stencil_bit (priv
->subcomposite_stencil_bit
); /* Relinquish any bitplane we previously used */
130 glStencilFunc (GL_ALWAYS
, 0, 0); /* Always pass stencil test */
131 glDisable (GL_STENCIL_TEST
); /* Disable Stencil test */
133 priv
->subcomposite_stencil_bit
= 0;
138 ghid_set_layer (const char *name
, int group
, int empty
)
140 render_priv
*priv
= gport
->render_priv
;
142 if (idx
>= 0 && idx
< max_group
)
144 int n
= PCB
->LayerGroups
.Number
[group
];
145 for (idx
= 0; idx
< n
-1; idx
++)
147 int ni
= PCB
->LayerGroups
.Entries
[group
][idx
];
148 if (ni
>= 0 && ni
< max_copper_layer
+ SILK_LAYER
149 && PCB
->Data
->Layer
[ni
].On
)
152 idx
= PCB
->LayerGroups
.Entries
[group
][idx
];
156 start_subcomposite ();
158 if (idx
>= 0 && idx
< max_copper_layer
+ SILK_LAYER
)
160 priv
->trans_lines
= true;
161 return PCB
->Data
->Layer
[idx
].On
;
165 switch (SL_TYPE (idx
))
168 return PCB
->InvisibleObjectsOn
;
171 return TEST_FLAG (SHOWMASKFLAG
, PCB
);
174 priv
->trans_lines
= true;
176 return PCB
->ElementOn
;
185 priv
->trans_lines
= true;
193 ghid_end_layer (void)
199 ghid_destroy_gc (hidGC gc
)
209 rv
= g_new0 (hid_gc_struct
, 1);
210 rv
->me_pointer
= &ghid_hid
;
211 rv
->colorname
= Settings
.BackgroundColor
;
212 rv
->alpha_mult
= 1.0;
217 ghid_draw_grid (BoxType
*drawn_area
)
219 if (Vz (PCB
->Grid
) < MIN_GRID_DISTANCE
)
222 if (gdk_color_parse (Settings
.GridColor
, &gport
->grid_color
))
224 gport
->grid_color
.red
^= gport
->bg_color
.red
;
225 gport
->grid_color
.green
^= gport
->bg_color
.green
;
226 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
229 glEnable (GL_COLOR_LOGIC_OP
);
232 glColor3f (gport
->grid_color
.red
/ 65535.,
233 gport
->grid_color
.green
/ 65535.,
234 gport
->grid_color
.blue
/ 65535.);
236 hidgl_draw_grid (drawn_area
, gport
->view
.coord_per_px
);
238 glDisable (GL_COLOR_LOGIC_OP
);
242 ghid_draw_bg_image (void)
244 static GLuint texture_handle
= 0;
246 if (!ghidgui
->bg_pixbuf
)
249 if (texture_handle
== 0)
251 int width
= gdk_pixbuf_get_width (ghidgui
->bg_pixbuf
);
252 int height
= gdk_pixbuf_get_height (ghidgui
->bg_pixbuf
);
253 int rowstride
= gdk_pixbuf_get_rowstride (ghidgui
->bg_pixbuf
);
254 int bits_per_sample
= gdk_pixbuf_get_bits_per_sample (ghidgui
->bg_pixbuf
);
255 int n_channels
= gdk_pixbuf_get_n_channels (ghidgui
->bg_pixbuf
);
256 unsigned char *pixels
= gdk_pixbuf_get_pixels (ghidgui
->bg_pixbuf
);
258 g_warn_if_fail (bits_per_sample
== 8);
259 g_warn_if_fail (rowstride
== width
* n_channels
);
261 glGenTextures (1, &texture_handle
);
262 glBindTexture (GL_TEXTURE_2D
, texture_handle
);
264 /* XXX: We should proabbly determine what the maxmimum texture supported is,
265 * and if our image is larger, shrink it down using GDK pixbuf routines
266 * rather than having it fail below.
269 glTexImage2D (GL_TEXTURE_2D
, 0, GL_RGB
, width
, height
, 0,
270 (n_channels
== 4) ? GL_RGBA
: GL_RGB
, GL_UNSIGNED_BYTE
, pixels
);
273 glBindTexture (GL_TEXTURE_2D
, texture_handle
);
275 glTexEnvf (GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_DECAL
);
276 glTexParameterf (GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
277 glTexParameterf (GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
278 glTexParameterf (GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
279 glTexParameterf (GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
280 glEnable (GL_TEXTURE_2D
);
282 /* Render a quad with the background as a texture */
285 glTexCoord2d (0., 0.);
286 glVertex3i (0, 0, 0);
287 glTexCoord2d (1., 0.);
288 glVertex3i (PCB
->MaxWidth
, 0, 0);
289 glTexCoord2d (1., 1.);
290 glVertex3i (PCB
->MaxWidth
, PCB
->MaxHeight
, 0);
291 glTexCoord2d (0., 1.);
292 glVertex3i (0, PCB
->MaxHeight
, 0);
295 glDisable (GL_TEXTURE_2D
);
299 ghid_use_mask (enum mask_mode mode
)
301 static int stencil_bit
= 0;
303 if (mode
== cur_mask
)
306 /* Flush out any existing geoemtry to be rendered */
307 hidgl_flush_triangles (&buffer
);
311 case HID_MASK_BEFORE
:
312 /* The HID asks not to receive this mask type, so warn if we get it */
313 g_return_if_reached ();
316 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */
317 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */
318 glEnable (GL_STENCIL_TEST
); /* Enable Stencil test */
319 stencil_bit
= hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */
320 glStencilFunc (GL_ALWAYS
, stencil_bit
, stencil_bit
); /* Always pass stencil test, write stencil_bit */
321 glStencilMask (stencil_bit
); /* Only write to our subcompositing stencil bitplane */
322 glStencilOp (GL_KEEP
, GL_KEEP
, GL_REPLACE
); /* Stencil pass => replace stencil value (with 1) */
326 /* Drawing operations as masked to areas where the stencil buffer is '0' */
327 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */
328 glStencilFunc (GL_GEQUAL
, 0, stencil_bit
); /* Draw only where our bit of the stencil buffer is clear */
329 glStencilOp (GL_KEEP
, GL_KEEP
, GL_KEEP
); /* Stencil buffer read only */
333 /* Disable stenciling */
334 hidgl_return_stencil_bit (stencil_bit
); /* Relinquish any bitplane we previously used */
335 glDisable (GL_STENCIL_TEST
); /* Disable Stencil test */
342 /* Config helper functions for when the user changes color preferences.
343 | set_special colors used in the gtkhid.
346 set_special_grid_color (void)
348 if (!gport
->colormap
)
350 gport
->grid_color
.red
^= gport
->bg_color
.red
;
351 gport
->grid_color
.green
^= gport
->bg_color
.green
;
352 gport
->grid_color
.blue
^= gport
->bg_color
.blue
;
356 ghid_set_special_colors (HID_Attribute
* ha
)
358 if (!ha
->name
|| !ha
->value
)
360 if (!strcmp (ha
->name
, "background-color"))
362 ghid_map_color_string (*(char **) ha
->value
, &gport
->bg_color
);
363 set_special_grid_color ();
365 else if (!strcmp (ha
->name
, "off-limit-color"))
367 ghid_map_color_string (*(char **) ha
->value
, &gport
->offlimits_color
);
369 else if (!strcmp (ha
->name
, "grid-color"))
371 ghid_map_color_string (*(char **) ha
->value
, &gport
->grid_color
);
372 set_special_grid_color ();
386 set_gl_color_for_gc (hidGC gc
)
388 render_priv
*priv
= gport
->render_priv
;
389 static void *cache
= NULL
;
394 if (priv
->current_colorname
!= NULL
&&
395 strcmp (priv
->current_colorname
, gc
->colorname
) == 0 &&
396 priv
->current_alpha_mult
== gc
->alpha_mult
)
399 free (priv
->current_colorname
);
400 priv
->current_colorname
= strdup (gc
->colorname
);
401 priv
->current_alpha_mult
= gc
->alpha_mult
;
403 if (gport
->colormap
== NULL
)
404 gport
->colormap
= gtk_widget_get_colormap (gport
->top_window
);
405 if (strcmp (gc
->colorname
, "erase") == 0)
407 r
= gport
->bg_color
.red
/ 65535.;
408 g
= gport
->bg_color
.green
/ 65535.;
409 b
= gport
->bg_color
.blue
/ 65535.;
412 else if (strcmp (gc
->colorname
, "drill") == 0)
414 r
= gport
->offlimits_color
.red
/ 65535.;
415 g
= gport
->offlimits_color
.green
/ 65535.;
416 b
= gport
->offlimits_color
.blue
/ 65535.;
421 if (hid_cache_color (0, gc
->colorname
, &cval
, &cache
))
422 cc
= (ColorCache
*) cval
.ptr
;
425 cc
= (ColorCache
*) malloc (sizeof (ColorCache
));
426 memset (cc
, 0, sizeof (*cc
));
428 hid_cache_color (1, gc
->colorname
, &cval
, &cache
);
433 if (gdk_color_parse (gc
->colorname
, &cc
->color
))
434 gdk_color_alloc (gport
->colormap
, &cc
->color
);
436 gdk_color_white (gport
->colormap
, &cc
->color
);
437 cc
->red
= cc
->color
.red
/ 65535.;
438 cc
->green
= cc
->color
.green
/ 65535.;
439 cc
->blue
= cc
->color
.blue
/ 65535.;
450 if (!priv
->trans_lines
)
453 if (g
> maxi
) maxi
= g
;
454 if (b
> maxi
) maxi
= b
;
455 mult
= MIN (1 / a
, 1 / maxi
);
463 if(!priv
->in_context
)
466 hidgl_flush_triangles (&buffer
);
467 glColor4d (r
, g
, b
, a
);
471 ghid_set_color (hidGC gc
, const char *name
)
473 gc
->colorname
= name
;
474 set_gl_color_for_gc (gc
);
478 ghid_set_alpha_mult (hidGC gc
, double alpha_mult
)
480 gc
->alpha_mult
= alpha_mult
;
481 set_gl_color_for_gc (gc
);
485 ghid_set_line_cap (hidGC gc
, EndCapStyle style
)
491 ghid_set_line_width (hidGC gc
, Coord width
)
498 ghid_set_draw_xor (hidGC gc
, int xor)
500 /* NOT IMPLEMENTED */
502 /* Only presently called when setting up a crosshair GC.
503 * We manage our own drawing model for that anyway. */
507 ghid_set_draw_faded (hidGC gc
, int faded
)
509 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc
, faded
);
513 ghid_set_line_cap_angle (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
515 printf ("ghid_set_line_cap_angle() -- not implemented\n");
519 ghid_invalidate_current_gc (void)
527 if (gc
->me_pointer
!= &ghid_hid
)
529 fprintf (stderr
, "Fatal: GC from another HID passed to GTK HID\n");
533 if (current_gc
== gc
)
538 set_gl_color_for_gc (gc
);
543 ghid_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
547 hidgl_draw_line (gc
->cap
, gc
->width
, x1
, y1
, x2
, y2
, gport
->view
.coord_per_px
);
551 ghid_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord xradius
, Coord yradius
,
552 Angle start_angle
, Angle delta_angle
)
556 hidgl_draw_arc (gc
->width
, cx
, cy
, xradius
, yradius
,
557 start_angle
, delta_angle
, gport
->view
.coord_per_px
);
561 ghid_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
565 hidgl_draw_rect (x1
, y1
, x2
, y2
);
570 ghid_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
574 hidgl_fill_circle (cx
, cy
, radius
, gport
->view
.coord_per_px
);
579 ghid_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
583 hidgl_fill_polygon (n_coords
, x
, y
);
587 ghid_fill_pcb_polygon (hidGC gc
, PolygonType
*poly
, const BoxType
*clip_box
)
590 if (TEST_FLAG (THINDRAWFLAG
, PCB
) || TEST_FLAG (THINDRAWPOLYFLAG
, PCB
))
591 ghid_set_alpha_mult (gc
, 0.25);
593 hidgl_fill_pcb_polygon (poly
, clip_box
, gport
->view
.coord_per_px
);
594 ghid_set_alpha_mult (gc
, 1.0);
598 * TODO: remove at next major revision
599 * This funciton was initially used to override the common function so that the
600 * hidgl HID would fill the thin-drawn polygons using transparency. Due to the
601 * implementation of opengl, all opaque objects must be drawn before transparent
602 * ones. As a result, in order to correctly draw objects in thin-draw mode, the
603 * drawing of objects and polygon outlines must be done first, prior to drawing
606 * The call to the common thindraw_pcb_polygon has been restored, and a second
607 * polygon draw phase has been added. The first phase only draws the outlines of
608 * the polygons and the second phase now draws the fill.
611 ghid_thindraw_pcb_polygon (hidGC gc
, PolygonType
*poly
, const BoxType
*clip_box
)
613 common_thindraw_pcb_polygon (gc
, poly
, clip_box
);
614 ghid_set_alpha_mult (gc
, 0.25);
615 gui
->graphics
->fill_pcb_polygon (gc
, poly
, clip_box
);
616 ghid_set_alpha_mult (gc
, 1.0);
620 ghid_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
624 hidgl_fill_rect (x1
, y1
, x2
, y2
);
628 ghid_invalidate_lr (Coord left
, Coord right
, Coord top
, Coord bottom
)
630 ghid_invalidate_all ();
633 #define MAX_ELAPSED (50. / 1000.) /* 50ms */
635 ghid_invalidate_all ()
637 render_priv
*priv
= gport
->render_priv
;
638 double elapsed
= g_timer_elapsed (priv
->time_since_expose
, NULL
);
640 ghid_draw_area_update (gport
, NULL
);
642 if (elapsed
> MAX_ELAPSED
)
643 gdk_window_process_all_updates ();
647 ghid_notify_crosshair_change (bool changes_complete
)
649 /* We sometimes get called before the GUI is up */
650 if (gport
->drawing_area
== NULL
)
653 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */
654 if (changes_complete
) ghid_invalidate_all ();
658 ghid_notify_mark_change (bool changes_complete
)
660 /* We sometimes get called before the GUI is up */
661 if (gport
->drawing_area
== NULL
)
664 /* FIXME: We could just invalidate the bounds of the mark? */
665 if (changes_complete
) ghid_invalidate_all ();
669 draw_right_cross (gint x
, gint y
, gint z
)
671 glVertex3i (x
, 0, z
);
672 glVertex3i (x
, PCB
->MaxHeight
, z
);
673 glVertex3i (0, y
, z
);
674 glVertex3i (PCB
->MaxWidth
, y
, z
);
678 draw_slanted_cross (gint x
, gint y
, gint z
)
682 x0
= x
+ (PCB
->MaxHeight
- y
);
683 x0
= MAX(0, MIN (x0
, PCB
->MaxWidth
));
685 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
686 y0
= y
+ (PCB
->MaxWidth
- x
);
687 y0
= MAX(0, MIN (y0
, PCB
->MaxHeight
));
689 y1
= MAX(0, MIN (y1
, PCB
->MaxHeight
));
690 glVertex3i (x0
, y0
, z
);
691 glVertex3i (x1
, y1
, z
);
693 x0
= x
- (PCB
->MaxHeight
- y
);
694 x0
= MAX(0, MIN (x0
, PCB
->MaxWidth
));
696 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
698 y0
= MAX(0, MIN (y0
, PCB
->MaxHeight
));
699 y1
= y
- (PCB
->MaxWidth
- x
);
700 y1
= MAX(0, MIN (y1
, PCB
->MaxHeight
));
701 glVertex3i (x0
, y0
, z
);
702 glVertex3i (x1
, y1
, z
);
706 draw_dozen_cross (gint x
, gint y
, gint z
)
709 gdouble tan60
= sqrt (3);
711 x0
= x
+ (PCB
->MaxHeight
- y
) / tan60
;
712 x0
= MAX(0, MIN (x0
, PCB
->MaxWidth
));
714 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
715 y0
= y
+ (PCB
->MaxWidth
- x
) * tan60
;
716 y0
= MAX(0, MIN (y0
, PCB
->MaxHeight
));
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
));
725 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
726 y0
= y
+ (PCB
->MaxWidth
- x
) / tan60
;
727 y0
= MAX(0, MIN (y0
, PCB
->MaxHeight
));
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
));
736 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
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
);
744 x0
= x
- (PCB
->MaxHeight
- y
) * tan60
;
745 x0
= MAX(0, MIN (x0
, PCB
->MaxWidth
));
747 x1
= MAX(0, MIN (x1
, PCB
->MaxWidth
));
749 y0
= MAX(0, MIN (y0
, PCB
->MaxHeight
));
750 y1
= y
- (PCB
->MaxWidth
- x
) / tan60
;
751 y1
= MAX(0, MIN (y1
, PCB
->MaxHeight
));
752 glVertex3i (x0
, y0
, z
);
753 glVertex3i (x1
, y1
, z
);
757 draw_crosshair (render_priv
*priv
)
760 static int done_once
= 0;
761 static GdkColor cross_color
;
766 /* FIXME: when CrossColor changed from config */
767 ghid_map_color_string (Settings
.CrossColor
, &cross_color
);
770 x
= gport
->crosshair_x
;
771 y
= gport
->crosshair_y
;
774 glEnable (GL_COLOR_LOGIC_OP
);
777 glColor3f (cross_color
.red
/ 65535.,
778 cross_color
.green
/ 65535.,
779 cross_color
.blue
/ 65535.);
783 draw_right_cross (x
, y
, z
);
784 if (Crosshair
.shape
== Union_Jack_Crosshair_Shape
)
785 draw_slanted_cross (x
, y
, z
);
786 if (Crosshair
.shape
== Dozen_Crosshair_Shape
)
787 draw_dozen_cross (x
, y
, z
);
791 glDisable (GL_COLOR_LOGIC_OP
);
795 ghid_init_renderer (int *argc
, char ***argv
, GHidPort
*port
)
799 port
->render_priv
= priv
= g_new0 (render_priv
, 1);
800 port
->render_priv
->crosshair_gc
= gui
->graphics
->make_gc ();
802 priv
->time_since_expose
= g_timer_new ();
804 gtk_gl_init(argc
, argv
);
806 /* setup GL-context */
807 priv
->glconfig
= gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA
|
808 GDK_GL_MODE_STENCIL
|
812 printf ("Could not setup GL-context!\n");
813 return; /* Should we abort? */
816 /* Setup HID function pointers specific to the GL renderer*/
817 ghid_hid
.end_layer
= ghid_end_layer
;
818 ghid_graphics
.fill_pcb_polygon
= ghid_fill_pcb_polygon
;
819 /*ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon;*/
823 ghid_shutdown_renderer (GHidPort
*port
)
825 render_priv
*priv
= port
->render_priv
;
827 gui
->graphics
->destroy_gc (priv
->crosshair_gc
);
828 ghid_cancel_lead_user ();
829 g_free (port
->render_priv
);
830 port
->render_priv
= NULL
;
834 ghid_init_drawing_widget (GtkWidget
*widget
, GHidPort
*port
)
836 render_priv
*priv
= port
->render_priv
;
838 gtk_widget_set_gl_capability (widget
,
846 ghid_drawing_area_configure_hook (GHidPort
*port
)
851 ghid_start_drawing (GHidPort
*port
, GtkWidget
*widget
)
853 GdkGLContext
*pGlContext
= gtk_widget_get_gl_context (widget
);
854 GdkGLDrawable
*pGlDrawable
= gtk_widget_get_gl_drawable (widget
);
856 /* make GL-context "current" */
857 if (!gdk_gl_drawable_gl_begin (pGlDrawable
, pGlContext
))
860 port
->render_priv
->in_context
= true;
866 ghid_end_drawing (GHidPort
*port
, GtkWidget
*widget
)
868 GdkGLDrawable
*pGlDrawable
= gtk_widget_get_gl_drawable (widget
);
870 if (gdk_gl_drawable_is_double_buffered (pGlDrawable
))
871 gdk_gl_drawable_swap_buffers (pGlDrawable
);
875 port
->render_priv
->in_context
= false;
877 /* end drawing to current GL-context */
878 gdk_gl_drawable_gl_end (pGlDrawable
);
882 ghid_screen_update (void)
888 ghid_drawing_area_expose_cb (GtkWidget
*widget
,
892 render_priv
*priv
= port
->render_priv
;
893 GtkAllocation allocation
;
901 gtk_widget_get_allocation (widget
, &allocation
);
903 ghid_start_drawing (port
, widget
);
904 hidgl_start_render ();
906 /* If we don't have any stencil bits available,
907 we can't use the hidgl polygon drawing routine */
908 /* TODO: We could use the GLU tessellator though */
909 if (hidgl_stencil_bits() == 0)
910 ghid_graphics
.fill_pcb_polygon
= common_fill_pcb_polygon
;
913 glBlendFunc (GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
915 glViewport (0, 0, allocation
.width
, allocation
.height
);
917 glEnable (GL_SCISSOR_TEST
);
918 glScissor (ev
->area
.x
,
919 allocation
.height
- ev
->area
.height
- ev
->area
.y
,
920 ev
->area
.width
, ev
->area
.height
);
922 glMatrixMode (GL_PROJECTION
);
924 glOrtho (0, allocation
.width
, allocation
.height
, 0, -100000, 100000);
925 glMatrixMode (GL_MODELVIEW
);
927 glTranslatef (widget
->allocation
.width
/ 2., widget
->allocation
.height
/ 2., 0);
928 glMultMatrixf ((GLfloat
*)view_matrix
);
929 glTranslatef (-widget
->allocation
.width
/ 2., -widget
->allocation
.height
/ 2., 0);
930 glScalef ((port
->view
.flip_x
? -1. : 1.) / port
->view
.coord_per_px
,
931 (port
->view
.flip_y
? -1. : 1.) / port
->view
.coord_per_px
,
932 ((port
->view
.flip_x
== port
->view
.flip_y
) ? 1. : -1.) / port
->view
.coord_per_px
);
933 glTranslatef (port
->view
.flip_x
? port
->view
.x0
- PCB
->MaxWidth
:
935 port
->view
.flip_y
? port
->view
.y0
- PCB
->MaxHeight
:
937 glGetFloatv (GL_MODELVIEW_MATRIX
, (GLfloat
*)last_modelview_matrix
);
939 glEnable (GL_STENCIL_TEST
);
940 glClearColor (port
->offlimits_color
.red
/ 65535.,
941 port
->offlimits_color
.green
/ 65535.,
942 port
->offlimits_color
.blue
/ 65535.,
946 glClear (GL_COLOR_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
947 hidgl_reset_stencil_usage ();
949 /* Disable the stencil test until we need it - otherwise it gets dirty */
950 glDisable (GL_STENCIL_TEST
);
952 glStencilFunc (GL_ALWAYS
, 0, 0);
954 /* Test the 8 corners of a cube spanning the event */
955 min_depth
= -50; /* FIXME */
956 max_depth
= 0; /* FIXME */
958 ghid_unproject_to_z_plane (ev
->area
.x
,
960 min_depth
, &new_x
, &new_y
);
961 max_x
= min_x
= new_x
;
962 max_y
= min_y
= new_y
;
964 ghid_unproject_to_z_plane (ev
->area
.x
,
966 max_depth
, &new_x
, &new_y
);
967 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
968 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
971 ghid_unproject_to_z_plane (ev
->area
.x
+ ev
->area
.width
,
973 min_depth
, &new_x
, &new_y
);
974 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
975 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
977 ghid_unproject_to_z_plane (ev
->area
.x
+ ev
->area
.width
, ev
->area
.y
,
978 max_depth
, &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
);
983 ghid_unproject_to_z_plane (ev
->area
.x
+ ev
->area
.width
,
984 ev
->area
.y
+ ev
->area
.height
,
985 min_depth
, &new_x
, &new_y
);
986 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
987 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
989 ghid_unproject_to_z_plane (ev
->area
.x
+ ev
->area
.width
,
990 ev
->area
.y
+ ev
->area
.height
,
991 max_depth
, &new_x
, &new_y
);
992 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
993 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
996 ghid_unproject_to_z_plane (ev
->area
.x
,
997 ev
->area
.y
+ ev
->area
.height
,
1000 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
1001 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
1003 ghid_unproject_to_z_plane (ev
->area
.x
,
1004 ev
->area
.y
+ ev
->area
.height
,
1007 min_x
= MIN (min_x
, new_x
); max_x
= MAX (max_x
, new_x
);
1008 min_y
= MIN (min_y
, new_y
); max_y
= MAX (max_y
, new_y
);
1010 region
.X1
= min_x
; region
.X2
= max_x
+ 1;
1011 region
.Y1
= min_y
; region
.Y2
= max_y
+ 1;
1013 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
1014 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
1015 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
1016 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
1018 glColor3f (port
->bg_color
.red
/ 65535.,
1019 port
->bg_color
.green
/ 65535.,
1020 port
->bg_color
.blue
/ 65535.);
1023 glVertex3i (0, 0, -50);
1024 glVertex3i (PCB
->MaxWidth
, 0, -50);
1025 glVertex3i (PCB
->MaxWidth
, PCB
->MaxHeight
, -50);
1026 glVertex3i (0, PCB
->MaxHeight
, -50);
1029 ghid_draw_bg_image ();
1031 ghid_invalidate_current_gc ();
1032 hid_expose_callback (&ghid_hid
, ®ion
, 0);
1033 hidgl_flush_triangles (&buffer
);
1035 ghid_graphics
.draw_grid (®ion
);
1037 ghid_invalidate_current_gc ();
1039 DrawAttached (priv
->crosshair_gc
);
1040 DrawMark (priv
->crosshair_gc
);
1041 hidgl_flush_triangles (&buffer
);
1043 draw_crosshair (priv
);
1044 hidgl_flush_triangles (&buffer
);
1046 draw_lead_user (priv
);
1048 hidgl_finish_render ();
1049 ghid_end_drawing (port
, widget
);
1051 g_timer_start (priv
->time_since_expose
);
1056 /* This realize callback is used to work around a crash bug in some mesa
1057 * versions (observed on a machine running the intel i965 driver. It isn't
1058 * obvious why it helps, but somehow fiddling with the GL context here solves
1059 * the issue. The problem appears to have been fixed in recent mesa versions.
1062 ghid_port_drawing_realize_cb (GtkWidget
*widget
, gpointer data
)
1064 GdkGLContext
*glcontext
= gtk_widget_get_gl_context (widget
);
1065 GdkGLDrawable
*gldrawable
= gtk_widget_get_gl_drawable (widget
);
1067 if (!gdk_gl_drawable_gl_begin (gldrawable
, glcontext
))
1070 gdk_gl_drawable_gl_end (gldrawable
);
1075 ghid_pinout_preview_expose (GtkWidget
*widget
,
1078 GhidPinoutPreview
*pinout
= GHID_PINOUT_PREVIEW (widget
);
1079 GtkAllocation allocation
;
1080 view_data save_view
;
1081 int save_width
, save_height
;
1082 Coord save_max_width
;
1083 Coord save_max_height
;
1086 save_view
= gport
->view
;
1087 save_width
= gport
->width
;
1088 save_height
= gport
->height
;
1089 save_max_width
= PCB
->MaxWidth
;
1090 save_max_height
= PCB
->MaxHeight
;
1092 /* Setup zoom factor for drawing routines */
1094 gtk_widget_get_allocation (widget
, &allocation
);
1095 xz
= (double) pinout
->x_max
/ allocation
.width
;
1096 yz
= (double) pinout
->y_max
/ allocation
.height
;
1098 gport
->view
.coord_per_px
= xz
;
1100 gport
->view
.coord_per_px
= yz
;
1102 gport
->width
= allocation
.width
;
1103 gport
->height
= allocation
.height
;
1104 gport
->view
.width
= allocation
.width
* gport
->view
.coord_per_px
;
1105 gport
->view
.height
= allocation
.height
* gport
->view
.coord_per_px
;
1106 gport
->view
.x0
= (pinout
->x_max
- gport
->view
.width
) / 2;
1107 gport
->view
.y0
= (pinout
->y_max
- gport
->view
.height
) / 2;
1108 PCB
->MaxWidth
= pinout
->x_max
;
1109 PCB
->MaxHeight
= pinout
->y_max
;
1111 ghid_start_drawing (gport
, widget
);
1112 hidgl_start_render ();
1114 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not
1115 * call set_layer() as appropriate for us to sub-composite rendering
1116 * from each layer when drawing a single element. If we leave alpha-
1117 * blending on, it means text and overlapping pads are rendered ugly.
1120 glEnable (GL_BLEND
);
1121 glBlendFunc (GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1124 glViewport (0, 0, allocation
.width
, allocation
.height
);
1126 #if 0 /* We disable the scissor test here, as it is interacting badly with
1127 * being handed expose events which don't cover the whole window.
1128 * As we have a double-buffered GL window, we end up with unintialised
1129 * contents remaining in the unpainted areas (outside the scissor
1130 * region), and these are being flipped onto the screen.
1132 * The debugging code below shows multiple expose events when the
1133 * window is shown the first time, some of which are very small.
1135 * XXX: There is clearly a perforamnce issue here, in that we may
1136 * be rendering the preview more times, and over a larger area
1137 * than is really required.
1140 glEnable (GL_SCISSOR_TEST
);
1141 glScissor (ev
->area
.x
,
1142 allocation
.height
- ev
->area
.height
- ev
->area
.y
,
1143 ev
->area
.width
, ev
->area
.height
);
1147 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n",
1148 ev
->area
.x
, ev
->area
.y
, ev
->area
.width
, ev
->area
.height
,
1150 (double)(allocation
.height
- ev
->area
.height
- ev
->area
.y
),
1151 (double)ev
->area
.width
,
1152 (double)ev
->area
.height
);
1155 glMatrixMode (GL_PROJECTION
);
1157 glOrtho (0, allocation
.width
, allocation
.height
, 0, -100000, 100000);
1158 glMatrixMode (GL_MODELVIEW
);
1160 glTranslatef (0.0f
, 0.0f
, -Z_NEAR
);
1162 glClearColor (gport
->bg_color
.red
/ 65535.,
1163 gport
->bg_color
.green
/ 65535.,
1164 gport
->bg_color
.blue
/ 65535.,
1168 glClear (GL_COLOR_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
1169 hidgl_reset_stencil_usage ();
1171 /* Disable the stencil test until we need it - otherwise it gets dirty */
1172 glDisable (GL_STENCIL_TEST
);
1174 glStencilFunc (GL_ALWAYS
, 0, 0);
1176 /* call the drawing routine */
1177 ghid_invalidate_current_gc ();
1179 glScalef ((gport
->view
.flip_x
? -1. : 1.) / gport
->view
.coord_per_px
,
1180 (gport
->view
.flip_y
? -1. : 1.) / gport
->view
.coord_per_px
,
1181 ((gport
->view
.flip_x
== gport
->view
.flip_y
) ? 1. : -1.) / gport
->view
.coord_per_px
);
1182 glTranslatef (gport
->view
.flip_x
? gport
->view
.x0
- PCB
->MaxWidth
:
1184 gport
->view
.flip_y
? gport
->view
.y0
- PCB
->MaxHeight
:
1185 -gport
->view
.y0
, 0);
1187 hid_expose_callback (&ghid_hid
, NULL
, pinout
->element
);
1188 hidgl_flush_triangles (&buffer
);
1191 hidgl_finish_render ();
1192 ghid_end_drawing (gport
, widget
);
1194 gport
->view
= save_view
;
1195 gport
->width
= save_width
;
1196 gport
->height
= save_height
;
1197 PCB
->MaxWidth
= save_max_width
;
1198 PCB
->MaxHeight
= save_max_height
;
1205 ghid_render_pixmap (int cx
, int cy
, double zoom
, int width
, int height
, int depth
)
1207 GdkGLConfig
*glconfig
;
1209 GdkGLPixmap
*glpixmap
;
1210 GdkGLContext
* glcontext
;
1211 GdkGLDrawable
* gldrawable
;
1212 view_data save_view
;
1213 int save_width
, save_height
;
1216 save_view
= gport
->view
;
1217 save_width
= gport
->width
;
1218 save_height
= gport
->height
;
1220 /* Setup rendering context for drawing routines
1223 glconfig
= gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB
|
1224 GDK_GL_MODE_STENCIL
|
1225 GDK_GL_MODE_SINGLE
);
1227 pixmap
= gdk_pixmap_new (NULL
, width
, height
, depth
);
1228 glpixmap
= gdk_pixmap_set_gl_capability (pixmap
, glconfig
, NULL
);
1229 gldrawable
= GDK_GL_DRAWABLE (glpixmap
);
1230 glcontext
= gdk_gl_context_new (gldrawable
, NULL
, TRUE
, GDK_GL_RGBA_TYPE
);
1232 /* Setup zoom factor for drawing routines */
1234 gport
->view
.coord_per_px
= zoom
;
1235 gport
->width
= width
;
1236 gport
->height
= height
;
1237 gport
->view
.width
= width
* gport
->view
.coord_per_px
;
1238 gport
->view
.height
= height
* gport
->view
.coord_per_px
;
1239 gport
->view
.x0
= gport
->view
.flip_x
? PCB
->MaxWidth
- cx
: cx
;
1240 gport
->view
.x0
-= gport
->view
.height
/ 2;
1241 gport
->view
.y0
= gport
->view
.flip_y
? PCB
->MaxHeight
- cy
: cy
;
1242 gport
->view
.y0
-= gport
->view
.width
/ 2;
1244 /* make GL-context "current" */
1245 if (!gdk_gl_drawable_gl_begin (gldrawable
, glcontext
)) {
1248 hidgl_start_render ();
1249 gport
->render_priv
->in_context
= true;
1251 glEnable (GL_BLEND
);
1252 glBlendFunc (GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1254 glViewport (0, 0, width
, height
);
1256 glEnable (GL_SCISSOR_TEST
);
1257 glScissor (0, 0, width
, height
);
1259 glMatrixMode (GL_PROJECTION
);
1261 glOrtho (0, width
, height
, 0, -100000, 100000);
1262 glMatrixMode (GL_MODELVIEW
);
1264 glTranslatef (0.0f
, 0.0f
, -Z_NEAR
);
1266 glClearColor (gport
->bg_color
.red
/ 65535.,
1267 gport
->bg_color
.green
/ 65535.,
1268 gport
->bg_color
.blue
/ 65535.,
1272 glClear (GL_COLOR_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT
);
1273 hidgl_reset_stencil_usage ();
1275 /* Disable the stencil test until we need it - otherwise it gets dirty */
1276 glDisable (GL_STENCIL_TEST
);
1278 glStencilFunc (GL_ALWAYS
, 0, 0);
1280 /* call the drawing routine */
1281 ghid_invalidate_current_gc ();
1283 glScalef ((gport
->view
.flip_x
? -1. : 1.) / gport
->view
.coord_per_px
,
1284 (gport
->view
.flip_y
? -1. : 1.) / gport
->view
.coord_per_px
,
1285 ((gport
->view
.flip_x
== gport
->view
.flip_y
) ? 1. : -1.) / gport
->view
.coord_per_px
);
1286 glTranslatef (gport
->view
.flip_x
? gport
->view
.x0
- PCB
->MaxWidth
:
1288 gport
->view
.flip_y
? gport
->view
.y0
- PCB
->MaxHeight
:
1289 -gport
->view
.y0
, 0);
1291 region
.X1
= MIN(Px(0), Px(gport
->width
+ 1));
1292 region
.Y1
= MIN(Py(0), Py(gport
->height
+ 1));
1293 region
.X2
= MAX(Px(0), Px(gport
->width
+ 1));
1294 region
.Y2
= MAX(Py(0), Py(gport
->height
+ 1));
1296 region
.X1
= MAX (0, MIN (PCB
->MaxWidth
, region
.X1
));
1297 region
.X2
= MAX (0, MIN (PCB
->MaxWidth
, region
.X2
));
1298 region
.Y1
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y1
));
1299 region
.Y2
= MAX (0, MIN (PCB
->MaxHeight
, region
.Y2
));
1301 hid_expose_callback (&ghid_hid
, ®ion
, NULL
);
1302 hidgl_flush_triangles (&buffer
);
1307 hidgl_finish_render ();
1309 /* end drawing to current GL-context */
1310 gport
->render_priv
->in_context
= false;
1311 gdk_gl_drawable_gl_end (gldrawable
);
1313 gdk_pixmap_unset_gl_capability (pixmap
);
1315 g_object_unref (glconfig
);
1316 g_object_unref (glcontext
);
1318 gport
->view
= save_view
;
1319 gport
->width
= save_width
;
1320 gport
->height
= save_height
;
1326 ghid_request_debug_draw (void)
1328 GHidPort
*port
= gport
;
1329 GtkWidget
*widget
= port
->drawing_area
;
1330 GtkAllocation allocation
;
1332 gtk_widget_get_allocation (widget
, &allocation
);
1334 ghid_start_drawing (port
, widget
);
1335 hidgl_start_render ();
1337 glViewport (0, 0, allocation
.width
, allocation
.height
);
1339 glMatrixMode (GL_PROJECTION
);
1341 glOrtho (0, allocation
.width
, allocation
.height
, 0, 0, 100);
1342 glMatrixMode (GL_MODELVIEW
);
1344 glTranslatef (0.0f
, 0.0f
, -Z_NEAR
);
1346 ghid_invalidate_current_gc ();
1348 /* Setup stenciling */
1349 glDisable (GL_STENCIL_TEST
);
1352 glScalef ((port
->view
.flip_x
? -1. : 1.) / port
->view
.coord_per_px
,
1353 (port
->view
.flip_y
? -1. : 1.) / port
->view
.coord_per_px
,
1354 ((gport
->view
.flip_x
== port
->view
.flip_y
) ? 1. : -1.) / gport
->view
.coord_per_px
);
1355 glTranslatef (port
->view
.flip_x
? port
->view
.x0
- PCB
->MaxWidth
:
1357 port
->view
.flip_y
? port
->view
.y0
- PCB
->MaxHeight
:
1360 return ghid_hid
.graphics
;
1364 ghid_flush_debug_draw (void)
1366 GtkWidget
*widget
= gport
->drawing_area
;
1367 GdkGLDrawable
*pGlDrawable
= gtk_widget_get_gl_drawable (widget
);
1369 hidgl_flush_triangles (&buffer
);
1371 if (gdk_gl_drawable_is_double_buffered (pGlDrawable
))
1372 gdk_gl_drawable_swap_buffers (pGlDrawable
);
1378 ghid_finish_debug_draw (void)
1380 hidgl_flush_triangles (&buffer
);
1383 hidgl_finish_render ();
1384 ghid_end_drawing (gport
, gport
->drawing_area
);
1388 determinant_2x2 (float m
[2][2])
1391 det
= m
[0][0] * m
[1][1] -
1398 determinant_4x4 (float m
[4][4])
1401 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] -
1402 m
[0][3] * m
[1][1] * m
[2][2] * m
[3][0]+m
[0][1] * m
[1][3] * m
[2][2] * m
[3][0] +
1403 m
[0][2] * m
[1][1] * m
[2][3] * m
[3][0]-m
[0][1] * m
[1][2] * m
[2][3] * m
[3][0] -
1404 m
[0][3] * m
[1][2] * m
[2][0] * m
[3][1]+m
[0][2] * m
[1][3] * m
[2][0] * m
[3][1] +
1405 m
[0][3] * m
[1][0] * m
[2][2] * m
[3][1]-m
[0][0] * m
[1][3] * m
[2][2] * m
[3][1] -
1406 m
[0][2] * m
[1][0] * m
[2][3] * m
[3][1]+m
[0][0] * m
[1][2] * m
[2][3] * m
[3][1] +
1407 m
[0][3] * m
[1][1] * m
[2][0] * m
[3][2]-m
[0][1] * m
[1][3] * m
[2][0] * m
[3][2] -
1408 m
[0][3] * m
[1][0] * m
[2][1] * m
[3][2]+m
[0][0] * m
[1][3] * m
[2][1] * m
[3][2] +
1409 m
[0][1] * m
[1][0] * m
[2][3] * m
[3][2]-m
[0][0] * m
[1][1] * m
[2][3] * m
[3][2] -
1410 m
[0][2] * m
[1][1] * m
[2][0] * m
[3][3]+m
[0][1] * m
[1][2] * m
[2][0] * m
[3][3] +
1411 m
[0][2] * m
[1][0] * m
[2][1] * m
[3][3]-m
[0][0] * m
[1][2] * m
[2][1] * m
[3][3] -
1412 m
[0][1] * m
[1][0] * m
[2][2] * m
[3][3]+m
[0][0] * m
[1][1] * m
[2][2] * m
[3][3];
1418 invert_2x2 (float m
[2][2], float out
[2][2])
1420 float scale
= 1 / determinant_2x2 (m
);
1421 out
[0][0] = m
[1][1] * scale
;
1422 out
[0][1] = -m
[0][1] * scale
;
1423 out
[1][0] = -m
[1][0] * scale
;
1424 out
[1][1] = m
[0][0] * scale
;
1429 invert_4x4 (float m
[4][4], float out
[4][4])
1431 float scale
= 1 / determinant_4x4 (m
);
1433 out
[0][0] = (m
[1][2] * m
[2][3] * m
[3][1] - m
[1][3] * m
[2][2] * m
[3][1] +
1434 m
[1][3] * m
[2][1] * m
[3][2] - m
[1][1] * m
[2][3] * m
[3][2] -
1435 m
[1][2] * m
[2][1] * m
[3][3] + m
[1][1] * m
[2][2] * m
[3][3]) * scale
;
1436 out
[0][1] = (m
[0][3] * m
[2][2] * m
[3][1] - m
[0][2] * m
[2][3] * m
[3][1] -
1437 m
[0][3] * m
[2][1] * m
[3][2] + m
[0][1] * m
[2][3] * m
[3][2] +
1438 m
[0][2] * m
[2][1] * m
[3][3] - m
[0][1] * m
[2][2] * m
[3][3]) * scale
;
1439 out
[0][2] = (m
[0][2] * m
[1][3] * m
[3][1] - m
[0][3] * m
[1][2] * m
[3][1] +
1440 m
[0][3] * m
[1][1] * m
[3][2] - m
[0][1] * m
[1][3] * m
[3][2] -
1441 m
[0][2] * m
[1][1] * m
[3][3] + m
[0][1] * m
[1][2] * m
[3][3]) * scale
;
1442 out
[0][3] = (m
[0][3] * m
[1][2] * m
[2][1] - m
[0][2] * m
[1][3] * m
[2][1] -
1443 m
[0][3] * m
[1][1] * m
[2][2] + m
[0][1] * m
[1][3] * m
[2][2] +
1444 m
[0][2] * m
[1][1] * m
[2][3] - m
[0][1] * m
[1][2] * m
[2][3]) * scale
;
1445 out
[1][0] = (m
[1][3] * m
[2][2] * m
[3][0] - m
[1][2] * m
[2][3] * m
[3][0] -
1446 m
[1][3] * m
[2][0] * m
[3][2] + m
[1][0] * m
[2][3] * m
[3][2] +
1447 m
[1][2] * m
[2][0] * m
[3][3] - m
[1][0] * m
[2][2] * m
[3][3]) * scale
;
1448 out
[1][1] = (m
[0][2] * m
[2][3] * m
[3][0] - m
[0][3] * m
[2][2] * m
[3][0] +
1449 m
[0][3] * m
[2][0] * m
[3][2] - m
[0][0] * m
[2][3] * m
[3][2] -
1450 m
[0][2] * m
[2][0] * m
[3][3] + m
[0][0] * m
[2][2] * m
[3][3]) * scale
;
1451 out
[1][2] = (m
[0][3] * m
[1][2] * m
[3][0] - m
[0][2] * m
[1][3] * m
[3][0] -
1452 m
[0][3] * m
[1][0] * m
[3][2] + m
[0][0] * m
[1][3] * m
[3][2] +
1453 m
[0][2] * m
[1][0] * m
[3][3] - m
[0][0] * m
[1][2] * m
[3][3]) * scale
;
1454 out
[1][3] = (m
[0][2] * m
[1][3] * m
[2][0] - m
[0][3] * m
[1][2] * m
[2][0] +
1455 m
[0][3] * m
[1][0] * m
[2][2] - m
[0][0] * m
[1][3] * m
[2][2] -
1456 m
[0][2] * m
[1][0] * m
[2][3] + m
[0][0] * m
[1][2] * m
[2][3]) * scale
;
1457 out
[2][0] = (m
[1][1] * m
[2][3] * m
[3][0] - m
[1][3] * m
[2][1] * m
[3][0] +
1458 m
[1][3] * m
[2][0] * m
[3][1] - m
[1][0] * m
[2][3] * m
[3][1] -
1459 m
[1][1] * m
[2][0] * m
[3][3] + m
[1][0] * m
[2][1] * m
[3][3]) * scale
;
1460 out
[2][1] = (m
[0][3] * m
[2][1] * m
[3][0] - m
[0][1] * m
[2][3] * m
[3][0] -
1461 m
[0][3] * m
[2][0] * m
[3][1] + m
[0][0] * m
[2][3] * m
[3][1] +
1462 m
[0][1] * m
[2][0] * m
[3][3] - m
[0][0] * m
[2][1] * m
[3][3]) * scale
;
1463 out
[2][2] = (m
[0][1] * m
[1][3] * m
[3][0] - m
[0][3] * m
[1][1] * m
[3][0] +
1464 m
[0][3] * m
[1][0] * m
[3][1] - m
[0][0] * m
[1][3] * m
[3][1] -
1465 m
[0][1] * m
[1][0] * m
[3][3] + m
[0][0] * m
[1][1] * m
[3][3]) * scale
;
1466 out
[2][3] = (m
[0][3] * m
[1][1] * m
[2][0] - m
[0][1] * m
[1][3] * m
[2][0] -
1467 m
[0][3] * m
[1][0] * m
[2][1] + m
[0][0] * m
[1][3] * m
[2][1] +
1468 m
[0][1] * m
[1][0] * m
[2][3] - m
[0][0] * m
[1][1] * m
[2][3]) * scale
;
1469 out
[3][0] = (m
[1][2] * m
[2][1] * m
[3][0] - m
[1][1] * m
[2][2] * m
[3][0] -
1470 m
[1][2] * m
[2][0] * m
[3][1] + m
[1][0] * m
[2][2] * m
[3][1] +
1471 m
[1][1] * m
[2][0] * m
[3][2] - m
[1][0] * m
[2][1] * m
[3][2]) * scale
;
1472 out
[3][1] = (m
[0][1] * m
[2][2] * m
[3][0] - m
[0][2] * m
[2][1] * m
[3][0] +
1473 m
[0][2] * m
[2][0] * m
[3][1] - m
[0][0] * m
[2][2] * m
[3][1] -
1474 m
[0][1] * m
[2][0] * m
[3][2] + m
[0][0] * m
[2][1] * m
[3][2]) * scale
;
1475 out
[3][2] = (m
[0][2] * m
[1][1] * m
[3][0] - m
[0][1] * m
[1][2] * m
[3][0] -
1476 m
[0][2] * m
[1][0] * m
[3][1] + m
[0][0] * m
[1][2] * m
[3][1] +
1477 m
[0][1] * m
[1][0] * m
[3][2] - m
[0][0] * m
[1][1] * m
[3][2]) * scale
;
1478 out
[3][3] = (m
[0][1] * m
[1][2] * m
[2][0] - m
[0][2] * m
[1][1] * m
[2][0] +
1479 m
[0][2] * m
[1][0] * m
[2][1] - m
[0][0] * m
[1][2] * m
[2][1] -
1480 m
[0][1] * m
[1][0] * m
[2][2] + m
[0][0] * m
[1][1] * m
[2][2]) * scale
;
1486 ghid_unproject_to_z_plane (int ex
, int ey
, Coord pcb_z
, Coord
*pcb_x
, Coord
*pcb_y
)
1489 float inv_mat
[2][2];
1493 ex = view_matrix[0][0] * vx +
1494 view_matrix[0][1] * vy +
1495 view_matrix[0][2] * vz +
1496 view_matrix[0][3] * 1;
1497 ey = view_matrix[1][0] * vx +
1498 view_matrix[1][1] * vy +
1499 view_matrix[1][2] * vz +
1500 view_matrix[1][3] * 1;
1501 UNKNOWN ez = view_matrix[2][0] * vx +
1502 view_matrix[2][1] * vy +
1503 view_matrix[2][2] * vz +
1504 view_matrix[2][3] * 1;
1506 ex - view_matrix[0][3] * 1
1507 - view_matrix[0][2] * vz
1508 = view_matrix[0][0] * vx +
1509 view_matrix[0][1] * vy;
1511 ey - view_matrix[1][3] * 1
1512 - view_matrix[1][2] * vz
1513 = view_matrix[1][0] * vx +
1514 view_matrix[1][1] * vy;
1517 /* NB: last_modelview_matrix is transposed in memory! */
1518 x
= (float)ex
- last_modelview_matrix
[3][0] * 1
1519 - last_modelview_matrix
[2][0] * pcb_z
;
1521 y
= (float)ey
- last_modelview_matrix
[3][1] * 1
1522 - last_modelview_matrix
[2][1] * pcb_z
;
1525 x = view_matrix[0][0] * vx +
1526 view_matrix[0][1] * vy;
1528 y = view_matrix[1][0] * vx +
1529 view_matrix[1][1] * vy;
1531 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x]
1532 [view_matrix[1][0] view_matrix[1][1]] [vy] [y]
1535 mat
[0][0] = last_modelview_matrix
[0][0];
1536 mat
[0][1] = last_modelview_matrix
[1][0];
1537 mat
[1][0] = last_modelview_matrix
[0][1];
1538 mat
[1][1] = last_modelview_matrix
[1][1];
1540 /* if (determinant_2x2 (mat) < 0.00001) */
1541 /* printf ("Determinant is quite small\n"); */
1543 invert_2x2 (mat
, inv_mat
);
1545 *pcb_x
= (int)(inv_mat
[0][0] * x
+ inv_mat
[0][1] * y
);
1546 *pcb_y
= (int)(inv_mat
[1][0] * x
+ inv_mat
[1][1] * y
);
1551 ghid_event_to_pcb_coords (int event_x
, int event_y
, Coord
*pcb_x
, Coord
*pcb_y
)
1553 ghid_unproject_to_z_plane (event_x
, event_y
, 0, pcb_x
, pcb_y
);
1559 ghid_pcb_to_event_coords (Coord pcb_x
, Coord pcb_y
, int *event_x
, int *event_y
)
1561 /* NB: last_modelview_matrix is transposed in memory */
1562 float w
= last_modelview_matrix
[0][3] * (float)pcb_x
+
1563 last_modelview_matrix
[1][3] * (float)pcb_y
+
1564 last_modelview_matrix
[2][3] * 0. +
1565 last_modelview_matrix
[3][3] * 1.;
1567 *event_x
= (last_modelview_matrix
[0][0] * (float)pcb_x
+
1568 last_modelview_matrix
[1][0] * (float)pcb_y
+
1569 last_modelview_matrix
[2][0] * 0. +
1570 last_modelview_matrix
[3][0] * 1.) / w
;
1571 *event_y
= (last_modelview_matrix
[0][1] * (float)pcb_x
+
1572 last_modelview_matrix
[1][1] * (float)pcb_y
+
1573 last_modelview_matrix
[2][1] * 0. +
1574 last_modelview_matrix
[3][1] * 1.) / w
;
1580 ghid_view_2d (void *ball
, gboolean view_2d
, gpointer userdata
)
1582 global_view_2d
= view_2d
;
1583 ghid_invalidate_all ();
1587 ghid_port_rotate (void *ball
, float *quarternion
, gpointer userdata
)
1593 build_rotmatrix (view_matrix
, quarternion
);
1596 for (row
= 0; row
< 4; row
++) {
1597 printf ("[ %f", view_matrix
[row
][0]);
1598 for (column
= 1; column
< 4; column
++) {
1599 printf (",\t%f", view_matrix
[row
][column
]);
1606 ghid_invalidate_all ();
1610 #define LEAD_USER_WIDTH 0.2 /* millimeters */
1611 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */
1612 #define LEAD_USER_VELOCITY 3. /* millimeters per second */
1613 #define LEAD_USER_ARC_COUNT 3
1614 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */
1615 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */
1616 #define LEAD_USER_COLOR_R 1.
1617 #define LEAD_USER_COLOR_G 1.
1618 #define LEAD_USER_COLOR_B 0.
1621 draw_lead_user (render_priv
*priv
)
1624 double radius
= priv
->lead_user_radius
;
1625 double width
= MM_TO_COORD (LEAD_USER_WIDTH
);
1626 double separation
= MM_TO_COORD (LEAD_USER_ARC_SEPARATION
);
1628 if (!priv
->lead_user
)
1631 glPushAttrib (GL_CURRENT_BIT
| GL_COLOR_BUFFER_BIT
);
1632 glEnable (GL_COLOR_LOGIC_OP
);
1634 glColor3f (LEAD_USER_COLOR_R
, LEAD_USER_COLOR_G
,LEAD_USER_COLOR_B
);
1637 /* arcs at the approrpriate radii */
1639 for (i
= 0; i
< LEAD_USER_ARC_COUNT
; i
++, radius
-= separation
)
1642 radius
+= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1644 /* Draw an arc at radius */
1645 hidgl_draw_arc (width
, priv
->lead_user_x
, priv
->lead_user_y
,
1646 radius
, radius
, 0, 360, gport
->view
.coord_per_px
);
1649 hidgl_flush_triangles (&buffer
);
1654 lead_user_cb (gpointer data
)
1656 render_priv
*priv
= data
;
1658 double elapsed_time
;
1660 /* Queue a redraw */
1661 ghid_invalidate_all ();
1664 elapsed_time
= g_timer_elapsed (priv
->lead_user_timer
, NULL
);
1665 g_timer_start (priv
->lead_user_timer
);
1667 step
= MM_TO_COORD (LEAD_USER_VELOCITY
* elapsed_time
);
1668 if (priv
->lead_user_radius
> step
)
1669 priv
->lead_user_radius
-= step
;
1671 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1677 ghid_lead_user_to_location (Coord x
, Coord y
)
1679 render_priv
*priv
= gport
->render_priv
;
1681 ghid_cancel_lead_user ();
1683 priv
->lead_user
= true;
1684 priv
->lead_user_x
= x
;
1685 priv
->lead_user_y
= y
;
1686 priv
->lead_user_radius
= MM_TO_COORD (LEAD_USER_INITIAL_RADIUS
);
1687 priv
->lead_user_timeout
= g_timeout_add (LEAD_USER_PERIOD
, lead_user_cb
, priv
);
1688 priv
->lead_user_timer
= g_timer_new ();
1692 ghid_cancel_lead_user (void)
1694 render_priv
*priv
= gport
->render_priv
;
1696 if (priv
->lead_user_timeout
)
1697 g_source_remove (priv
->lead_user_timeout
);
1699 if (priv
->lead_user_timer
)
1700 g_timer_destroy (priv
->lead_user_timer
);
1702 if (priv
->lead_user
)
1703 ghid_invalidate_all ();
1705 priv
->lead_user_timeout
= 0;
1706 priv
->lead_user_timer
= NULL
;
1707 priv
->lead_user
= false;