pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 #ifdef HAVE_CONFIG_H 00002 #include "config.h" 00003 #endif 00004 00005 #include <stdio.h> 00006 00007 #include "crosshair.h" 00008 #include "clip.h" 00009 #include "../hidint.h" 00010 #include "gui.h" 00011 #include "gui-pinout-preview.h" 00012 00013 /* The Linux OpenGL ABI 1.0 spec requires that we define 00014 * GL_GLEXT_PROTOTYPES before including gl.h or glx.h for extensions 00015 * in order to get prototypes: 00016 * http://www.opengl.org/registry/ABI/ 00017 */ 00018 #define GL_GLEXT_PROTOTYPES 1 00019 00020 /* This follows autoconf's recommendation for the AX_CHECK_GL macro 00021 https://www.gnu.org/software/autoconf-archive/ax_check_gl.html */ 00022 #if defined HAVE_WINDOWS_H && defined _WIN32 00023 # include <windows.h> 00024 #endif 00025 #if defined HAVE_GL_GL_H 00026 # include <GL/gl.h> 00027 #elif defined HAVE_OPENGL_GL_H 00028 # include <OpenGL/gl.h> 00029 #else 00030 # error autoconf couldnt find gl.h 00031 #endif 00032 00033 #include <gtk/gtkgl.h> 00034 #include "hid/common/hidgl.h" 00035 00036 #include "hid/common/draw_helpers.h" 00037 #include "hid/common/trackball.h" 00038 00039 #ifdef HAVE_LIBDMALLOC 00040 #include <dmalloc.h> 00041 #endif 00042 00043 extern HID ghid_hid; 00044 extern HID_DRAW ghid_graphics; 00045 00046 static hidGC current_gc = NULL; 00047 00048 /* Sets gport->u_gc to the "right" GC to use (wrt mask or window) 00049 */ 00050 #define USE_GC(gc) if (!use_gc(gc)) return 00051 00052 static enum mask_mode cur_mask = HID_MASK_OFF; 00053 static GLfloat view_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0}, 00054 {0.0, 1.0, 0.0, 0.0}, 00055 {0.0, 0.0, 1.0, 0.0}, 00056 {0.0, 0.0, 0.0, 1.0}}; 00057 static GLfloat last_modelview_matrix[4][4] = {{1.0, 0.0, 0.0, 0.0}, 00058 {0.0, 1.0, 0.0, 0.0}, 00059 {0.0, 0.0, 1.0, 0.0}, 00060 {0.0, 0.0, 0.0, 1.0}}; 00061 static int global_view_2d = 1; 00062 00063 typedef struct render_priv { 00064 GdkGLConfig *glconfig; 00065 bool trans_lines; 00066 bool in_context; 00067 int subcomposite_stencil_bit; 00068 char *current_colorname; 00069 double current_alpha_mult; 00070 GTimer *time_since_expose; 00071 00072 /* Feature for leading the user to a particular location */ 00073 guint lead_user_timeout; 00074 GTimer *lead_user_timer; 00075 bool lead_user; 00076 Coord lead_user_radius; 00077 Coord lead_user_x; 00078 Coord lead_user_y; 00079 00080 hidGC crosshair_gc; 00081 } render_priv; 00082 00083 00084 typedef struct hid_gc_struct 00085 { 00086 HID *me_pointer; 00087 00088 const char *colorname; 00089 double alpha_mult; 00090 Coord width; 00091 gint cap, join; 00092 } 00093 hid_gc_struct; 00094 00095 00096 static void draw_lead_user (render_priv *priv); 00097 static void ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y); 00098 00099 00100 static void 00101 start_subcomposite (void) 00102 { 00103 render_priv *priv = gport->render_priv; 00104 int stencil_bit; 00105 00106 /* Flush out any existing geoemtry to be rendered */ 00107 hidgl_flush_triangles (&buffer); 00108 00109 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */ 00110 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */ 00111 00112 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */ 00113 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */ 00114 glStencilFunc (GL_GREATER, stencil_bit, stencil_bit); /* Pass stencil test if our assigned bit is clear */ 00115 00116 priv->subcomposite_stencil_bit = stencil_bit; 00117 } 00118 00119 static void 00120 end_subcomposite (void) 00121 { 00122 render_priv *priv = gport->render_priv; 00123 00124 /* Flush out any existing geoemtry to be rendered */ 00125 hidgl_flush_triangles (&buffer); 00126 00127 hidgl_return_stencil_bit (priv->subcomposite_stencil_bit); /* Relinquish any bitplane we previously used */ 00128 00129 glStencilMask (0); 00130 glStencilFunc (GL_ALWAYS, 0, 0); /* Always pass stencil test */ 00131 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */ 00132 00133 priv->subcomposite_stencil_bit = 0; 00134 } 00135 00136 00137 int 00138 ghid_set_layer (const char *name, int group, int empty) 00139 { 00140 render_priv *priv = gport->render_priv; 00141 int idx = group; 00142 if (idx >= 0 && idx < max_group) 00143 { 00144 int n = PCB->LayerGroups.Number[group]; 00145 for (idx = 0; idx < n-1; idx ++) 00146 { 00147 int ni = PCB->LayerGroups.Entries[group][idx]; 00148 if (ni >= 0 && ni < max_copper_layer + SILK_LAYER 00149 && PCB->Data->Layer[ni].On) 00150 break; 00151 } 00152 idx = PCB->LayerGroups.Entries[group][idx]; 00153 } 00154 00155 end_subcomposite (); 00156 start_subcomposite (); 00157 00158 if (idx >= 0 && idx < max_copper_layer + SILK_LAYER) 00159 { 00160 priv->trans_lines = true; 00161 return PCB->Data->Layer[idx].On; 00162 } 00163 if (idx < 0) 00164 { 00165 switch (SL_TYPE (idx)) 00166 { 00167 case SL_INVISIBLE: 00168 return PCB->InvisibleObjectsOn; 00169 case SL_MASK: 00170 if (SL_MYSIDE (idx)) 00171 return TEST_FLAG (SHOWMASKFLAG, PCB); 00172 return 0; 00173 case SL_SILK: 00174 priv->trans_lines = true; 00175 if (SL_MYSIDE (idx)) 00176 return PCB->ElementOn; 00177 return 0; 00178 case SL_ASSY: 00179 return 0; 00180 case SL_PDRILL: 00181 case SL_UDRILL: 00182 return 1; 00183 case SL_RATS: 00184 if (PCB->RatOn) 00185 priv->trans_lines = true; 00186 return PCB->RatOn; 00187 } 00188 } 00189 return 0; 00190 } 00191 00192 static void 00193 ghid_end_layer (void) 00194 { 00195 end_subcomposite (); 00196 } 00197 00198 void 00199 ghid_destroy_gc (hidGC gc) 00200 { 00201 g_free (gc); 00202 } 00203 00204 hidGC 00205 ghid_make_gc (void) 00206 { 00207 hidGC rv; 00208 00209 rv = g_new0 (hid_gc_struct, 1); 00210 rv->me_pointer = &ghid_hid; 00211 rv->colorname = Settings.BackgroundColor; 00212 rv->alpha_mult = 1.0; 00213 return rv; 00214 } 00215 00216 void 00217 ghid_draw_grid (BoxType *drawn_area) 00218 { 00219 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE) 00220 return; 00221 00222 if (gdk_color_parse (Settings.GridColor, &gport->grid_color)) 00223 { 00224 gport->grid_color.red ^= gport->bg_color.red; 00225 gport->grid_color.green ^= gport->bg_color.green; 00226 gport->grid_color.blue ^= gport->bg_color.blue; 00227 } 00228 00229 glEnable (GL_COLOR_LOGIC_OP); 00230 glLogicOp (GL_XOR); 00231 00232 glColor3f (gport->grid_color.red / 65535., 00233 gport->grid_color.green / 65535., 00234 gport->grid_color.blue / 65535.); 00235 00236 hidgl_draw_grid (drawn_area); 00237 00238 glDisable (GL_COLOR_LOGIC_OP); 00239 } 00240 00241 static void 00242 ghid_draw_bg_image (void) 00243 { 00244 static GLuint texture_handle = 0; 00245 00246 if (!ghidgui->bg_pixbuf) 00247 return; 00248 00249 if (texture_handle == 0) 00250 { 00251 int width = gdk_pixbuf_get_width (ghidgui->bg_pixbuf); 00252 int height = gdk_pixbuf_get_height (ghidgui->bg_pixbuf); 00253 int rowstride = gdk_pixbuf_get_rowstride (ghidgui->bg_pixbuf); 00254 int bits_per_sample = gdk_pixbuf_get_bits_per_sample (ghidgui->bg_pixbuf); 00255 int n_channels = gdk_pixbuf_get_n_channels (ghidgui->bg_pixbuf); 00256 unsigned char *pixels = gdk_pixbuf_get_pixels (ghidgui->bg_pixbuf); 00257 00258 g_warn_if_fail (bits_per_sample == 8); 00259 g_warn_if_fail (rowstride == width * n_channels); 00260 00261 glGenTextures (1, &texture_handle); 00262 glBindTexture (GL_TEXTURE_2D, texture_handle); 00263 00264 /* XXX: We should proabbly determine what the maxmimum texture supported is, 00265 * and if our image is larger, shrink it down using GDK pixbuf routines 00266 * rather than having it fail below. 00267 */ 00268 00269 glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, 00270 (n_channels == 4) ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, pixels); 00271 } 00272 00273 glBindTexture (GL_TEXTURE_2D, texture_handle); 00274 00275 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); 00276 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00277 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00278 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00279 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00280 glEnable (GL_TEXTURE_2D); 00281 00282 /* Render a quad with the background as a texture */ 00283 00284 glBegin (GL_QUADS); 00285 glTexCoord2d (0., 0.); 00286 glVertex3i (0, 0, 0); 00287 glTexCoord2d (1., 0.); 00288 glVertex3i (PCB->MaxWidth, 0, 0); 00289 glTexCoord2d (1., 1.); 00290 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, 0); 00291 glTexCoord2d (0., 1.); 00292 glVertex3i (0, PCB->MaxHeight, 0); 00293 glEnd (); 00294 00295 glDisable (GL_TEXTURE_2D); 00296 } 00297 00298 void 00299 ghid_use_mask (enum mask_mode mode) 00300 { 00301 static int stencil_bit = 0; 00302 00303 if (mode == cur_mask) 00304 return; 00305 00306 /* Flush out any existing geoemtry to be rendered */ 00307 hidgl_flush_triangles (&buffer); 00308 00309 switch (mode) 00310 { 00311 case HID_MASK_BEFORE: 00312 /* The HID asks not to receive this mask type, so warn if we get it */ 00313 g_return_if_reached (); 00314 00315 case HID_MASK_CLEAR: 00316 /* Write '1' to the stencil buffer where the solder-mask should not be drawn. */ 00317 glColorMask (0, 0, 0, 0); /* Disable writting in color buffer */ 00318 glEnable (GL_STENCIL_TEST); /* Enable Stencil test */ 00319 stencil_bit = hidgl_assign_clear_stencil_bit(); /* Get a new (clean) bitplane to stencil with */ 00320 glStencilFunc (GL_ALWAYS, stencil_bit, stencil_bit); /* Always pass stencil test, write stencil_bit */ 00321 glStencilMask (stencil_bit); /* Only write to our subcompositing stencil bitplane */ 00322 glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE); /* Stencil pass => replace stencil value (with 1) */ 00323 break; 00324 00325 case HID_MASK_AFTER: 00326 /* Drawing operations as masked to areas where the stencil buffer is '0' */ 00327 glColorMask (1, 1, 1, 1); /* Enable drawing of r, g, b & a */ 00328 glStencilFunc (GL_GEQUAL, 0, stencil_bit); /* Draw only where our bit of the stencil buffer is clear */ 00329 glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); /* Stencil buffer read only */ 00330 break; 00331 00332 case HID_MASK_OFF: 00333 /* Disable stenciling */ 00334 hidgl_return_stencil_bit (stencil_bit); /* Relinquish any bitplane we previously used */ 00335 glDisable (GL_STENCIL_TEST); /* Disable Stencil test */ 00336 break; 00337 } 00338 cur_mask = mode; 00339 } 00340 00341 00342 /* Config helper functions for when the user changes color preferences. 00343 | set_special colors used in the gtkhid. 00344 */ 00345 static void 00346 set_special_grid_color (void) 00347 { 00348 if (!gport->colormap) 00349 return; 00350 gport->grid_color.red ^= gport->bg_color.red; 00351 gport->grid_color.green ^= gport->bg_color.green; 00352 gport->grid_color.blue ^= gport->bg_color.blue; 00353 } 00354 00355 void 00356 ghid_set_special_colors (HID_Attribute * ha) 00357 { 00358 if (!ha->name || !ha->value) 00359 return; 00360 if (!strcmp (ha->name, "background-color")) 00361 { 00362 ghid_map_color_string (*(char **) ha->value, &gport->bg_color); 00363 set_special_grid_color (); 00364 } 00365 else if (!strcmp (ha->name, "off-limit-color")) 00366 { 00367 ghid_map_color_string (*(char **) ha->value, &gport->offlimits_color); 00368 } 00369 else if (!strcmp (ha->name, "grid-color")) 00370 { 00371 ghid_map_color_string (*(char **) ha->value, &gport->grid_color); 00372 set_special_grid_color (); 00373 } 00374 } 00375 00376 typedef struct 00377 { 00378 int color_set; 00379 GdkColor color; 00380 double red; 00381 double green; 00382 double blue; 00383 } ColorCache; 00384 00385 static void 00386 set_gl_color_for_gc (hidGC gc) 00387 { 00388 render_priv *priv = gport->render_priv; 00389 static void *cache = NULL; 00390 hidval cval; 00391 ColorCache *cc; 00392 double r, g, b, a; 00393 00394 if (priv->current_colorname != NULL && 00395 strcmp (priv->current_colorname, gc->colorname) == 0 && 00396 priv->current_alpha_mult == gc->alpha_mult) 00397 return; 00398 00399 free (priv->current_colorname); 00400 priv->current_colorname = strdup (gc->colorname); 00401 priv->current_alpha_mult = gc->alpha_mult; 00402 00403 if (gport->colormap == NULL) 00404 gport->colormap = gtk_widget_get_colormap (gport->top_window); 00405 if (strcmp (gc->colorname, "erase") == 0) 00406 { 00407 r = gport->bg_color.red / 65535.; 00408 g = gport->bg_color.green / 65535.; 00409 b = gport->bg_color.blue / 65535.; 00410 a = 1.0; 00411 } 00412 else if (strcmp (gc->colorname, "drill") == 0) 00413 { 00414 r = gport->offlimits_color.red / 65535.; 00415 g = gport->offlimits_color.green / 65535.; 00416 b = gport->offlimits_color.blue / 65535.; 00417 a = 0.85; 00418 } 00419 else 00420 { 00421 if (hid_cache_color (0, gc->colorname, &cval, &cache)) 00422 cc = (ColorCache *) cval.ptr; 00423 else 00424 { 00425 cc = (ColorCache *) malloc (sizeof (ColorCache)); 00426 memset (cc, 0, sizeof (*cc)); 00427 cval.ptr = cc; 00428 hid_cache_color (1, gc->colorname, &cval, &cache); 00429 } 00430 00431 if (!cc->color_set) 00432 { 00433 if (gdk_color_parse (gc->colorname, &cc->color)) 00434 gdk_color_alloc (gport->colormap, &cc->color); 00435 else 00436 gdk_color_white (gport->colormap, &cc->color); 00437 cc->red = cc->color.red / 65535.; 00438 cc->green = cc->color.green / 65535.; 00439 cc->blue = cc->color.blue / 65535.; 00440 cc->color_set = 1; 00441 } 00442 r = cc->red; 00443 g = cc->green; 00444 b = cc->blue; 00445 a = 0.7; 00446 } 00447 if (1) { 00448 double maxi, mult; 00449 a *= gc->alpha_mult; 00450 if (!priv->trans_lines) 00451 a = 1.0; 00452 maxi = r; 00453 if (g > maxi) maxi = g; 00454 if (b > maxi) maxi = b; 00455 mult = MIN (1 / a, 1 / maxi); 00456 #if 1 00457 r = r * mult; 00458 g = g * mult; 00459 b = b * mult; 00460 #endif 00461 } 00462 00463 if(!priv->in_context) 00464 return; 00465 00466 hidgl_flush_triangles (&buffer); 00467 glColor4d (r, g, b, a); 00468 } 00469 00470 void 00471 ghid_set_color (hidGC gc, const char *name) 00472 { 00473 gc->colorname = name; 00474 set_gl_color_for_gc (gc); 00475 } 00476 00477 void 00478 ghid_set_alpha_mult (hidGC gc, double alpha_mult) 00479 { 00480 gc->alpha_mult = alpha_mult; 00481 set_gl_color_for_gc (gc); 00482 } 00483 00484 void 00485 ghid_set_line_cap (hidGC gc, EndCapStyle style) 00486 { 00487 gc->cap = style; 00488 } 00489 00490 void 00491 ghid_set_line_width (hidGC gc, Coord width) 00492 { 00493 gc->width = width; 00494 } 00495 00496 00497 void 00498 ghid_set_draw_xor (hidGC gc, int xor) 00499 { 00500 /* NOT IMPLEMENTED */ 00501 00502 /* Only presently called when setting up a crosshair GC. 00503 * We manage our own drawing model for that anyway. */ 00504 } 00505 00506 void 00507 ghid_set_draw_faded (hidGC gc, int faded) 00508 { 00509 printf ("ghid_set_draw_faded(%p,%d) -- not implemented\n", gc, faded); 00510 } 00511 00512 void 00513 ghid_set_line_cap_angle (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00514 { 00515 printf ("ghid_set_line_cap_angle() -- not implemented\n"); 00516 } 00517 00518 static void 00519 ghid_invalidate_current_gc (void) 00520 { 00521 current_gc = NULL; 00522 } 00523 00524 static int 00525 use_gc (hidGC gc) 00526 { 00527 if (gc->me_pointer != &ghid_hid) 00528 { 00529 fprintf (stderr, "Fatal: GC from another HID passed to GTK HID\n"); 00530 abort (); 00531 } 00532 00533 if (current_gc == gc) 00534 return 1; 00535 00536 current_gc = gc; 00537 00538 set_gl_color_for_gc (gc); 00539 return 1; 00540 } 00541 00542 void 00543 ghid_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00544 { 00545 USE_GC (gc); 00546 00547 hidgl_draw_line (gc->cap, gc->width, x1, y1, x2, y2, gport->view.coord_per_px); 00548 } 00549 00550 void 00551 ghid_draw_arc (hidGC gc, Coord cx, Coord cy, Coord xradius, Coord yradius, 00552 Angle start_angle, Angle delta_angle) 00553 { 00554 USE_GC (gc); 00555 00556 hidgl_draw_arc (gc->width, cx, cy, xradius, yradius, 00557 start_angle, delta_angle, gport->view.coord_per_px); 00558 } 00559 00560 void 00561 ghid_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00562 { 00563 USE_GC (gc); 00564 00565 hidgl_draw_rect (x1, y1, x2, y2); 00566 } 00567 00568 00569 void 00570 ghid_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius) 00571 { 00572 USE_GC (gc); 00573 00574 hidgl_fill_circle (cx, cy, radius, gport->view.coord_per_px); 00575 } 00576 00577 00578 void 00579 ghid_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y) 00580 { 00581 USE_GC (gc); 00582 00583 hidgl_fill_polygon (n_coords, x, y); 00584 } 00585 00586 void 00587 ghid_fill_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box) 00588 { 00589 USE_GC (gc); 00590 00591 hidgl_fill_pcb_polygon (poly, clip_box, gport->view.coord_per_px); 00592 } 00593 00594 void 00595 ghid_thindraw_pcb_polygon (hidGC gc, PolygonType *poly, const BoxType *clip_box) 00596 { 00597 common_thindraw_pcb_polygon (gc, poly, clip_box); 00598 ghid_set_alpha_mult (gc, 0.25); 00599 gui->graphics->fill_pcb_polygon (gc, poly, clip_box); 00600 ghid_set_alpha_mult (gc, 1.0); 00601 } 00602 00603 void 00604 ghid_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00605 { 00606 USE_GC (gc); 00607 00608 hidgl_fill_rect (x1, y1, x2, y2); 00609 } 00610 00611 void 00612 ghid_invalidate_lr (Coord left, Coord right, Coord top, Coord bottom) 00613 { 00614 ghid_invalidate_all (); 00615 } 00616 00617 #define MAX_ELAPSED (50. / 1000.) /* 50ms */ 00618 void 00619 ghid_invalidate_all () 00620 { 00621 render_priv *priv = gport->render_priv; 00622 double elapsed = g_timer_elapsed (priv->time_since_expose, NULL); 00623 00624 ghid_draw_area_update (gport, NULL); 00625 00626 if (elapsed > MAX_ELAPSED) 00627 gdk_window_process_all_updates (); 00628 } 00629 00630 void 00631 ghid_notify_crosshair_change (bool changes_complete) 00632 { 00633 /* We sometimes get called before the GUI is up */ 00634 if (gport->drawing_area == NULL) 00635 return; 00636 00637 /* FIXME: We could just invalidate the bounds of the crosshair attached objects? */ 00638 if (changes_complete) ghid_invalidate_all (); 00639 } 00640 00641 void 00642 ghid_notify_mark_change (bool changes_complete) 00643 { 00644 /* We sometimes get called before the GUI is up */ 00645 if (gport->drawing_area == NULL) 00646 return; 00647 00648 /* FIXME: We could just invalidate the bounds of the mark? */ 00649 if (changes_complete) ghid_invalidate_all (); 00650 } 00651 00652 static void 00653 draw_right_cross (gint x, gint y, gint z) 00654 { 00655 glVertex3i (x, 0, z); 00656 glVertex3i (x, PCB->MaxHeight, z); 00657 glVertex3i (0, y, z); 00658 glVertex3i (PCB->MaxWidth, y, z); 00659 } 00660 00661 static void 00662 draw_slanted_cross (gint x, gint y, gint z) 00663 { 00664 gint x0, y0, x1, y1; 00665 00666 x0 = x + (PCB->MaxHeight - y); 00667 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00668 x1 = x - y; 00669 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00670 y0 = y + (PCB->MaxWidth - x); 00671 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00672 y1 = y - x; 00673 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00674 glVertex3i (x0, y0, z); 00675 glVertex3i (x1, y1, z); 00676 00677 x0 = x - (PCB->MaxHeight - y); 00678 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00679 x1 = x + y; 00680 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00681 y0 = y + x; 00682 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00683 y1 = y - (PCB->MaxWidth - x); 00684 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00685 glVertex3i (x0, y0, z); 00686 glVertex3i (x1, y1, z); 00687 } 00688 00689 static void 00690 draw_dozen_cross (gint x, gint y, gint z) 00691 { 00692 gint x0, y0, x1, y1; 00693 gdouble tan60 = sqrt (3); 00694 00695 x0 = x + (PCB->MaxHeight - y) / tan60; 00696 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00697 x1 = x - y / tan60; 00698 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00699 y0 = y + (PCB->MaxWidth - x) * tan60; 00700 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00701 y1 = y - x * tan60; 00702 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00703 glVertex3i (x0, y0, z); 00704 glVertex3i (x1, y1, z); 00705 00706 x0 = x + (PCB->MaxHeight - y) * tan60; 00707 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00708 x1 = x - y * tan60; 00709 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00710 y0 = y + (PCB->MaxWidth - x) / tan60; 00711 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00712 y1 = y - x / tan60; 00713 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00714 glVertex3i (x0, y0, z); 00715 glVertex3i (x1, y1, z); 00716 00717 x0 = x - (PCB->MaxHeight - y) / tan60; 00718 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00719 x1 = x + y / tan60; 00720 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00721 y0 = y + x * tan60; 00722 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00723 y1 = y - (PCB->MaxWidth - x) * tan60; 00724 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00725 glVertex3i (x0, y0, z); 00726 glVertex3i (x1, y1, z); 00727 00728 x0 = x - (PCB->MaxHeight - y) * tan60; 00729 x0 = MAX(0, MIN (x0, PCB->MaxWidth)); 00730 x1 = x + y * tan60; 00731 x1 = MAX(0, MIN (x1, PCB->MaxWidth)); 00732 y0 = y + x / tan60; 00733 y0 = MAX(0, MIN (y0, PCB->MaxHeight)); 00734 y1 = y - (PCB->MaxWidth - x) / tan60; 00735 y1 = MAX(0, MIN (y1, PCB->MaxHeight)); 00736 glVertex3i (x0, y0, z); 00737 glVertex3i (x1, y1, z); 00738 } 00739 00740 static void 00741 draw_crosshair (render_priv *priv) 00742 { 00743 gint x, y, z; 00744 static int done_once = 0; 00745 static GdkColor cross_color; 00746 00747 if (!done_once) 00748 { 00749 done_once = 1; 00750 /* FIXME: when CrossColor changed from config */ 00751 ghid_map_color_string (Settings.CrossColor, &cross_color); 00752 } 00753 00754 x = gport->crosshair_x; 00755 y = gport->crosshair_y; 00756 z = 0; 00757 00758 glEnable (GL_COLOR_LOGIC_OP); 00759 glLogicOp (GL_XOR); 00760 00761 glColor3f (cross_color.red / 65535., 00762 cross_color.green / 65535., 00763 cross_color.blue / 65535.); 00764 00765 glBegin (GL_LINES); 00766 00767 draw_right_cross (x, y, z); 00768 if (Crosshair.shape == Union_Jack_Crosshair_Shape) 00769 draw_slanted_cross (x, y, z); 00770 if (Crosshair.shape == Dozen_Crosshair_Shape) 00771 draw_dozen_cross (x, y, z); 00772 00773 glEnd (); 00774 00775 glDisable (GL_COLOR_LOGIC_OP); 00776 } 00777 00778 void 00779 ghid_init_renderer (int *argc, char ***argv, GHidPort *port) 00780 { 00781 render_priv *priv; 00782 00783 port->render_priv = priv = g_new0 (render_priv, 1); 00784 port->render_priv->crosshair_gc = gui->graphics->make_gc (); 00785 00786 priv->time_since_expose = g_timer_new (); 00787 00788 gtk_gl_init(argc, argv); 00789 00790 /* setup GL-context */ 00791 priv->glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGBA | 00792 GDK_GL_MODE_STENCIL | 00793 GDK_GL_MODE_DOUBLE); 00794 if (!priv->glconfig) 00795 { 00796 printf ("Could not setup GL-context!\n"); 00797 return; /* Should we abort? */ 00798 } 00799 00800 /* Setup HID function pointers specific to the GL renderer*/ 00801 ghid_hid.end_layer = ghid_end_layer; 00802 ghid_graphics.fill_pcb_polygon = ghid_fill_pcb_polygon; 00803 ghid_graphics.thindraw_pcb_polygon = ghid_thindraw_pcb_polygon; 00804 } 00805 00806 void 00807 ghid_shutdown_renderer (GHidPort *port) 00808 { 00809 render_priv *priv = port->render_priv; 00810 00811 gui->graphics->destroy_gc (priv->crosshair_gc); 00812 ghid_cancel_lead_user (); 00813 g_free (port->render_priv); 00814 port->render_priv = NULL; 00815 } 00816 00817 void 00818 ghid_init_drawing_widget (GtkWidget *widget, GHidPort *port) 00819 { 00820 render_priv *priv = port->render_priv; 00821 00822 gtk_widget_set_gl_capability (widget, 00823 priv->glconfig, 00824 NULL, 00825 TRUE, 00826 GDK_GL_RGBA_TYPE); 00827 } 00828 00829 void 00830 ghid_drawing_area_configure_hook (GHidPort *port) 00831 { 00832 } 00833 00834 gboolean 00835 ghid_start_drawing (GHidPort *port, GtkWidget *widget) 00836 { 00837 GdkGLContext *pGlContext = gtk_widget_get_gl_context (widget); 00838 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); 00839 00840 /* make GL-context "current" */ 00841 if (!gdk_gl_drawable_gl_begin (pGlDrawable, pGlContext)) 00842 return FALSE; 00843 00844 port->render_priv->in_context = true; 00845 00846 return TRUE; 00847 } 00848 00849 void 00850 ghid_end_drawing (GHidPort *port, GtkWidget *widget) 00851 { 00852 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); 00853 00854 if (gdk_gl_drawable_is_double_buffered (pGlDrawable)) 00855 gdk_gl_drawable_swap_buffers (pGlDrawable); 00856 else 00857 glFlush (); 00858 00859 port->render_priv->in_context = false; 00860 00861 /* end drawing to current GL-context */ 00862 gdk_gl_drawable_gl_end (pGlDrawable); 00863 } 00864 00865 void 00866 ghid_screen_update (void) 00867 { 00868 } 00869 00870 #define Z_NEAR 3.0 00871 gboolean 00872 ghid_drawing_area_expose_cb (GtkWidget *widget, 00873 GdkEventExpose *ev, 00874 GHidPort *port) 00875 { 00876 render_priv *priv = port->render_priv; 00877 GtkAllocation allocation; 00878 BoxType region; 00879 Coord min_x, min_y; 00880 Coord max_x, max_y; 00881 Coord new_x, new_y; 00882 Coord min_depth; 00883 Coord max_depth; 00884 00885 gtk_widget_get_allocation (widget, &allocation); 00886 00887 ghid_start_drawing (port, widget); 00888 hidgl_start_render (); 00889 00890 /* If we don't have any stencil bits available, 00891 we can't use the hidgl polygon drawing routine */ 00892 /* TODO: We could use the GLU tessellator though */ 00893 if (hidgl_stencil_bits() == 0) 00894 ghid_graphics.fill_pcb_polygon = common_fill_pcb_polygon; 00895 00896 glEnable (GL_BLEND); 00897 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 00898 00899 glViewport (0, 0, allocation.width, allocation.height); 00900 00901 glEnable (GL_SCISSOR_TEST); 00902 glScissor (ev->area.x, 00903 allocation.height - ev->area.height - ev->area.y, 00904 ev->area.width, ev->area.height); 00905 00906 glMatrixMode (GL_PROJECTION); 00907 glLoadIdentity (); 00908 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000); 00909 glMatrixMode (GL_MODELVIEW); 00910 glLoadIdentity (); 00911 glTranslatef (widget->allocation.width / 2., widget->allocation.height / 2., 0); 00912 glMultMatrixf ((GLfloat *)view_matrix); 00913 glTranslatef (-widget->allocation.width / 2., -widget->allocation.height / 2., 0); 00914 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px, 00915 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px, 00916 ((port->view.flip_x == port->view.flip_y) ? 1. : -1.) / port->view.coord_per_px); 00917 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth : 00918 -port->view.x0, 00919 port->view.flip_y ? port->view.y0 - PCB->MaxHeight : 00920 -port->view.y0, 0); 00921 glGetFloatv (GL_MODELVIEW_MATRIX, (GLfloat *)last_modelview_matrix); 00922 00923 glEnable (GL_STENCIL_TEST); 00924 glClearColor (port->offlimits_color.red / 65535., 00925 port->offlimits_color.green / 65535., 00926 port->offlimits_color.blue / 65535., 00927 1.); 00928 glStencilMask (~0); 00929 glClearStencil (0); 00930 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 00931 hidgl_reset_stencil_usage (); 00932 00933 /* Disable the stencil test until we need it - otherwise it gets dirty */ 00934 glDisable (GL_STENCIL_TEST); 00935 glStencilMask (0); 00936 glStencilFunc (GL_ALWAYS, 0, 0); 00937 00938 /* Test the 8 corners of a cube spanning the event */ 00939 min_depth = -50; /* FIXME */ 00940 max_depth = 0; /* FIXME */ 00941 00942 ghid_unproject_to_z_plane (ev->area.x, 00943 ev->area.y, 00944 min_depth, &new_x, &new_y); 00945 max_x = min_x = new_x; 00946 max_y = min_y = new_y; 00947 00948 ghid_unproject_to_z_plane (ev->area.x, 00949 ev->area.y, 00950 max_depth, &new_x, &new_y); 00951 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00952 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00953 00954 /* */ 00955 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, 00956 ev->area.y, 00957 min_depth, &new_x, &new_y); 00958 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00959 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00960 00961 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, ev->area.y, 00962 max_depth, &new_x, &new_y); 00963 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00964 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00965 00966 /* */ 00967 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, 00968 ev->area.y + ev->area.height, 00969 min_depth, &new_x, &new_y); 00970 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00971 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00972 00973 ghid_unproject_to_z_plane (ev->area.x + ev->area.width, 00974 ev->area.y + ev->area.height, 00975 max_depth, &new_x, &new_y); 00976 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00977 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00978 00979 /* */ 00980 ghid_unproject_to_z_plane (ev->area.x, 00981 ev->area.y + ev->area.height, 00982 min_depth, 00983 &new_x, &new_y); 00984 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00985 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00986 00987 ghid_unproject_to_z_plane (ev->area.x, 00988 ev->area.y + ev->area.height, 00989 max_depth, 00990 &new_x, &new_y); 00991 min_x = MIN (min_x, new_x); max_x = MAX (max_x, new_x); 00992 min_y = MIN (min_y, new_y); max_y = MAX (max_y, new_y); 00993 00994 region.X1 = min_x; region.X2 = max_x + 1; 00995 region.Y1 = min_y; region.Y2 = max_y + 1; 00996 00997 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); 00998 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); 00999 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); 01000 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); 01001 01002 glColor3f (port->bg_color.red / 65535., 01003 port->bg_color.green / 65535., 01004 port->bg_color.blue / 65535.); 01005 01006 glBegin (GL_QUADS); 01007 glVertex3i (0, 0, -50); 01008 glVertex3i (PCB->MaxWidth, 0, -50); 01009 glVertex3i (PCB->MaxWidth, PCB->MaxHeight, -50); 01010 glVertex3i (0, PCB->MaxHeight, -50); 01011 glEnd (); 01012 01013 ghid_draw_bg_image (); 01014 01015 ghid_invalidate_current_gc (); 01016 hid_expose_callback (&ghid_hid, ®ion, 0); 01017 hidgl_flush_triangles (&buffer); 01018 01019 ghid_graphics.draw_grid (®ion); 01020 01021 ghid_invalidate_current_gc (); 01022 01023 DrawAttached (priv->crosshair_gc); 01024 DrawMark (priv->crosshair_gc); 01025 hidgl_flush_triangles (&buffer); 01026 01027 draw_crosshair (priv); 01028 hidgl_flush_triangles (&buffer); 01029 01030 draw_lead_user (priv); 01031 01032 hidgl_finish_render (); 01033 ghid_end_drawing (port, widget); 01034 01035 g_timer_start (priv->time_since_expose); 01036 01037 return FALSE; 01038 } 01039 01040 /* This realize callback is used to work around a crash bug in some mesa 01041 * versions (observed on a machine running the intel i965 driver. It isn't 01042 * obvious why it helps, but somehow fiddling with the GL context here solves 01043 * the issue. The problem appears to have been fixed in recent mesa versions. 01044 */ 01045 void 01046 ghid_port_drawing_realize_cb (GtkWidget *widget, gpointer data) 01047 { 01048 GdkGLContext *glcontext = gtk_widget_get_gl_context (widget); 01049 GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget); 01050 01051 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) 01052 return; 01053 01054 gdk_gl_drawable_gl_end (gldrawable); 01055 return; 01056 } 01057 01058 gboolean 01059 ghid_pinout_preview_expose (GtkWidget *widget, 01060 GdkEventExpose *ev) 01061 { 01062 GhidPinoutPreview *pinout = GHID_PINOUT_PREVIEW (widget); 01063 GtkAllocation allocation; 01064 view_data save_view; 01065 int save_width, save_height; 01066 Coord save_max_width; 01067 Coord save_max_height; 01068 double xz, yz; 01069 01070 save_view = gport->view; 01071 save_width = gport->width; 01072 save_height = gport->height; 01073 save_max_width = PCB->MaxWidth; 01074 save_max_height = PCB->MaxHeight; 01075 01076 /* Setup zoom factor for drawing routines */ 01077 01078 gtk_widget_get_allocation (widget, &allocation); 01079 xz = (double) pinout->x_max / allocation.width; 01080 yz = (double) pinout->y_max / allocation.height; 01081 if (xz > yz) 01082 gport->view.coord_per_px = xz; 01083 else 01084 gport->view.coord_per_px = yz; 01085 01086 gport->width = allocation.width; 01087 gport->height = allocation.height; 01088 gport->view.width = allocation.width * gport->view.coord_per_px; 01089 gport->view.height = allocation.height * gport->view.coord_per_px; 01090 gport->view.x0 = (pinout->x_max - gport->view.width) / 2; 01091 gport->view.y0 = (pinout->y_max - gport->view.height) / 2; 01092 PCB->MaxWidth = pinout->x_max; 01093 PCB->MaxHeight = pinout->y_max; 01094 01095 ghid_start_drawing (gport, widget); 01096 hidgl_start_render (); 01097 01098 #if 0 /* We disable alpha blending here, as hid_expose_callback() does not 01099 * call set_layer() as appropriate for us to sub-composite rendering 01100 * from each layer when drawing a single element. If we leave alpha- 01101 * blending on, it means text and overlapping pads are rendered ugly. 01102 */ 01103 01104 glEnable (GL_BLEND); 01105 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 01106 #endif 01107 01108 glViewport (0, 0, allocation.width, allocation.height); 01109 01110 #if 0 /* We disable the scissor test here, as it is interacting badly with 01111 * being handed expose events which don't cover the whole window. 01112 * As we have a double-buffered GL window, we end up with unintialised 01113 * contents remaining in the unpainted areas (outside the scissor 01114 * region), and these are being flipped onto the screen. 01115 * 01116 * The debugging code below shows multiple expose events when the 01117 * window is shown the first time, some of which are very small. 01118 * 01119 * XXX: There is clearly a perforamnce issue here, in that we may 01120 * be rendering the preview more times, and over a larger area 01121 * than is really required. 01122 */ 01123 01124 glEnable (GL_SCISSOR_TEST); 01125 glScissor (ev->area.x, 01126 allocation.height - ev->area.height - ev->area.y, 01127 ev->area.width, ev->area.height); 01128 #endif 01129 01130 #ifdef DEBUG 01131 printf ("EVT: %i, %i, w=%i, h=%i, Scissor setup: glScissor (%f, %f, %f, %f);\n", 01132 ev->area.x, ev->area.y, ev->area.width, ev->area.height, 01133 (double)ev->area.x, 01134 (double)(allocation.height - ev->area.height - ev->area.y), 01135 (double)ev->area.width, 01136 (double)ev->area.height); 01137 #endif 01138 01139 glMatrixMode (GL_PROJECTION); 01140 glLoadIdentity (); 01141 glOrtho (0, allocation.width, allocation.height, 0, -100000, 100000); 01142 glMatrixMode (GL_MODELVIEW); 01143 glLoadIdentity (); 01144 glTranslatef (0.0f, 0.0f, -Z_NEAR); 01145 01146 glClearColor (gport->bg_color.red / 65535., 01147 gport->bg_color.green / 65535., 01148 gport->bg_color.blue / 65535., 01149 1.); 01150 glStencilMask (~0); 01151 glClearStencil (0); 01152 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 01153 hidgl_reset_stencil_usage (); 01154 01155 /* Disable the stencil test until we need it - otherwise it gets dirty */ 01156 glDisable (GL_STENCIL_TEST); 01157 glStencilMask (0); 01158 glStencilFunc (GL_ALWAYS, 0, 0); 01159 01160 /* call the drawing routine */ 01161 ghid_invalidate_current_gc (); 01162 glPushMatrix (); 01163 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px, 01164 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px, 01165 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); 01166 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth : 01167 -gport->view.x0, 01168 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight : 01169 -gport->view.y0, 0); 01170 01171 hid_expose_callback (&ghid_hid, NULL, pinout->element); 01172 hidgl_flush_triangles (&buffer); 01173 glPopMatrix (); 01174 01175 hidgl_finish_render (); 01176 ghid_end_drawing (gport, widget); 01177 01178 gport->view = save_view; 01179 gport->width = save_width; 01180 gport->height = save_height; 01181 PCB->MaxWidth = save_max_width; 01182 PCB->MaxHeight = save_max_height; 01183 01184 return FALSE; 01185 } 01186 01187 01188 GdkPixmap * 01189 ghid_render_pixmap (int cx, int cy, double zoom, int width, int height, int depth) 01190 { 01191 GdkGLConfig *glconfig; 01192 GdkPixmap *pixmap; 01193 GdkGLPixmap *glpixmap; 01194 GdkGLContext* glcontext; 01195 GdkGLDrawable* gldrawable; 01196 view_data save_view; 01197 int save_width, save_height; 01198 BoxType region; 01199 01200 save_view = gport->view; 01201 save_width = gport->width; 01202 save_height = gport->height; 01203 01204 /* Setup rendering context for drawing routines 01205 */ 01206 01207 glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB | 01208 GDK_GL_MODE_STENCIL | 01209 GDK_GL_MODE_SINGLE); 01210 01211 pixmap = gdk_pixmap_new (NULL, width, height, depth); 01212 glpixmap = gdk_pixmap_set_gl_capability (pixmap, glconfig, NULL); 01213 gldrawable = GDK_GL_DRAWABLE (glpixmap); 01214 glcontext = gdk_gl_context_new (gldrawable, NULL, TRUE, GDK_GL_RGBA_TYPE); 01215 01216 /* Setup zoom factor for drawing routines */ 01217 01218 gport->view.coord_per_px = zoom; 01219 gport->width = width; 01220 gport->height = height; 01221 gport->view.width = width * gport->view.coord_per_px; 01222 gport->view.height = height * gport->view.coord_per_px; 01223 gport->view.x0 = gport->view.flip_x ? PCB->MaxWidth - cx : cx; 01224 gport->view.x0 -= gport->view.height / 2; 01225 gport->view.y0 = gport->view.flip_y ? PCB->MaxHeight - cy : cy; 01226 gport->view.y0 -= gport->view.width / 2; 01227 01228 /* make GL-context "current" */ 01229 if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext)) { 01230 return NULL; 01231 } 01232 hidgl_start_render (); 01233 gport->render_priv->in_context = true; 01234 01235 glEnable (GL_BLEND); 01236 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 01237 01238 glViewport (0, 0, width, height); 01239 01240 glEnable (GL_SCISSOR_TEST); 01241 glScissor (0, 0, width, height); 01242 01243 glMatrixMode (GL_PROJECTION); 01244 glLoadIdentity (); 01245 glOrtho (0, width, height, 0, -100000, 100000); 01246 glMatrixMode (GL_MODELVIEW); 01247 glLoadIdentity (); 01248 glTranslatef (0.0f, 0.0f, -Z_NEAR); 01249 01250 glClearColor (gport->bg_color.red / 65535., 01251 gport->bg_color.green / 65535., 01252 gport->bg_color.blue / 65535., 01253 1.); 01254 glStencilMask (~0); 01255 glClearStencil (0); 01256 glClear (GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 01257 hidgl_reset_stencil_usage (); 01258 01259 /* Disable the stencil test until we need it - otherwise it gets dirty */ 01260 glDisable (GL_STENCIL_TEST); 01261 glStencilMask (0); 01262 glStencilFunc (GL_ALWAYS, 0, 0); 01263 01264 /* call the drawing routine */ 01265 ghid_invalidate_current_gc (); 01266 glPushMatrix (); 01267 glScalef ((gport->view.flip_x ? -1. : 1.) / gport->view.coord_per_px, 01268 (gport->view.flip_y ? -1. : 1.) / gport->view.coord_per_px, 01269 ((gport->view.flip_x == gport->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); 01270 glTranslatef (gport->view.flip_x ? gport->view.x0 - PCB->MaxWidth : 01271 -gport->view.x0, 01272 gport->view.flip_y ? gport->view.y0 - PCB->MaxHeight : 01273 -gport->view.y0, 0); 01274 01275 region.X1 = MIN(Px(0), Px(gport->width + 1)); 01276 region.Y1 = MIN(Py(0), Py(gport->height + 1)); 01277 region.X2 = MAX(Px(0), Px(gport->width + 1)); 01278 region.Y2 = MAX(Py(0), Py(gport->height + 1)); 01279 01280 region.X1 = MAX (0, MIN (PCB->MaxWidth, region.X1)); 01281 region.X2 = MAX (0, MIN (PCB->MaxWidth, region.X2)); 01282 region.Y1 = MAX (0, MIN (PCB->MaxHeight, region.Y1)); 01283 region.Y2 = MAX (0, MIN (PCB->MaxHeight, region.Y2)); 01284 01285 hid_expose_callback (&ghid_hid, ®ion, NULL); 01286 hidgl_flush_triangles (&buffer); 01287 glPopMatrix (); 01288 01289 glFlush (); 01290 01291 hidgl_finish_render (); 01292 01293 /* end drawing to current GL-context */ 01294 gport->render_priv->in_context = false; 01295 gdk_gl_drawable_gl_end (gldrawable); 01296 01297 gdk_pixmap_unset_gl_capability (pixmap); 01298 01299 g_object_unref (glconfig); 01300 g_object_unref (glcontext); 01301 01302 gport->view = save_view; 01303 gport->width = save_width; 01304 gport->height = save_height; 01305 01306 return pixmap; 01307 } 01308 01309 HID_DRAW * 01310 ghid_request_debug_draw (void) 01311 { 01312 GHidPort *port = gport; 01313 GtkWidget *widget = port->drawing_area; 01314 GtkAllocation allocation; 01315 01316 gtk_widget_get_allocation (widget, &allocation); 01317 01318 ghid_start_drawing (port, widget); 01319 hidgl_start_render (); 01320 01321 glViewport (0, 0, allocation.width, allocation.height); 01322 01323 glMatrixMode (GL_PROJECTION); 01324 glLoadIdentity (); 01325 glOrtho (0, allocation.width, allocation.height, 0, 0, 100); 01326 glMatrixMode (GL_MODELVIEW); 01327 glLoadIdentity (); 01328 glTranslatef (0.0f, 0.0f, -Z_NEAR); 01329 01330 ghid_invalidate_current_gc (); 01331 01332 /* Setup stenciling */ 01333 glDisable (GL_STENCIL_TEST); 01334 01335 glPushMatrix (); 01336 glScalef ((port->view.flip_x ? -1. : 1.) / port->view.coord_per_px, 01337 (port->view.flip_y ? -1. : 1.) / port->view.coord_per_px, 01338 ((gport->view.flip_x == port->view.flip_y) ? 1. : -1.) / gport->view.coord_per_px); 01339 glTranslatef (port->view.flip_x ? port->view.x0 - PCB->MaxWidth : 01340 -port->view.x0, 01341 port->view.flip_y ? port->view.y0 - PCB->MaxHeight : 01342 -port->view.y0, 0); 01343 01344 return ghid_hid.graphics; 01345 } 01346 01347 void 01348 ghid_flush_debug_draw (void) 01349 { 01350 GtkWidget *widget = gport->drawing_area; 01351 GdkGLDrawable *pGlDrawable = gtk_widget_get_gl_drawable (widget); 01352 01353 hidgl_flush_triangles (&buffer); 01354 01355 if (gdk_gl_drawable_is_double_buffered (pGlDrawable)) 01356 gdk_gl_drawable_swap_buffers (pGlDrawable); 01357 else 01358 glFlush (); 01359 } 01360 01361 void 01362 ghid_finish_debug_draw (void) 01363 { 01364 hidgl_flush_triangles (&buffer); 01365 glPopMatrix (); 01366 01367 hidgl_finish_render (); 01368 ghid_end_drawing (gport, gport->drawing_area); 01369 } 01370 01371 static float 01372 determinant_2x2 (float m[2][2]) 01373 { 01374 float det; 01375 det = m[0][0] * m[1][1] - 01376 m[0][1] * m[1][0]; 01377 return det; 01378 } 01379 01380 #if 0 01381 static float 01382 determinant_4x4 (float m[4][4]) 01383 { 01384 float det; 01385 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] - 01386 m[0][3] * m[1][1] * m[2][2] * m[3][0]+m[0][1] * m[1][3] * m[2][2] * m[3][0] + 01387 m[0][2] * m[1][1] * m[2][3] * m[3][0]-m[0][1] * m[1][2] * m[2][3] * m[3][0] - 01388 m[0][3] * m[1][2] * m[2][0] * m[3][1]+m[0][2] * m[1][3] * m[2][0] * m[3][1] + 01389 m[0][3] * m[1][0] * m[2][2] * m[3][1]-m[0][0] * m[1][3] * m[2][2] * m[3][1] - 01390 m[0][2] * m[1][0] * m[2][3] * m[3][1]+m[0][0] * m[1][2] * m[2][3] * m[3][1] + 01391 m[0][3] * m[1][1] * m[2][0] * m[3][2]-m[0][1] * m[1][3] * m[2][0] * m[3][2] - 01392 m[0][3] * m[1][0] * m[2][1] * m[3][2]+m[0][0] * m[1][3] * m[2][1] * m[3][2] + 01393 m[0][1] * m[1][0] * m[2][3] * m[3][2]-m[0][0] * m[1][1] * m[2][3] * m[3][2] - 01394 m[0][2] * m[1][1] * m[2][0] * m[3][3]+m[0][1] * m[1][2] * m[2][0] * m[3][3] + 01395 m[0][2] * m[1][0] * m[2][1] * m[3][3]-m[0][0] * m[1][2] * m[2][1] * m[3][3] - 01396 m[0][1] * m[1][0] * m[2][2] * m[3][3]+m[0][0] * m[1][1] * m[2][2] * m[3][3]; 01397 return det; 01398 } 01399 #endif 01400 01401 static void 01402 invert_2x2 (float m[2][2], float out[2][2]) 01403 { 01404 float scale = 1 / determinant_2x2 (m); 01405 out[0][0] = m[1][1] * scale; 01406 out[0][1] = -m[0][1] * scale; 01407 out[1][0] = -m[1][0] * scale; 01408 out[1][1] = m[0][0] * scale; 01409 } 01410 01411 #if 0 01412 static void 01413 invert_4x4 (float m[4][4], float out[4][4]) 01414 { 01415 float scale = 1 / determinant_4x4 (m); 01416 01417 out[0][0] = (m[1][2] * m[2][3] * m[3][1] - m[1][3] * m[2][2] * m[3][1] + 01418 m[1][3] * m[2][1] * m[3][2] - m[1][1] * m[2][3] * m[3][2] - 01419 m[1][2] * m[2][1] * m[3][3] + m[1][1] * m[2][2] * m[3][3]) * scale; 01420 out[0][1] = (m[0][3] * m[2][2] * m[3][1] - m[0][2] * m[2][3] * m[3][1] - 01421 m[0][3] * m[2][1] * m[3][2] + m[0][1] * m[2][3] * m[3][2] + 01422 m[0][2] * m[2][1] * m[3][3] - m[0][1] * m[2][2] * m[3][3]) * scale; 01423 out[0][2] = (m[0][2] * m[1][3] * m[3][1] - m[0][3] * m[1][2] * m[3][1] + 01424 m[0][3] * m[1][1] * m[3][2] - m[0][1] * m[1][3] * m[3][2] - 01425 m[0][2] * m[1][1] * m[3][3] + m[0][1] * m[1][2] * m[3][3]) * scale; 01426 out[0][3] = (m[0][3] * m[1][2] * m[2][1] - m[0][2] * m[1][3] * m[2][1] - 01427 m[0][3] * m[1][1] * m[2][2] + m[0][1] * m[1][3] * m[2][2] + 01428 m[0][2] * m[1][1] * m[2][3] - m[0][1] * m[1][2] * m[2][3]) * scale; 01429 out[1][0] = (m[1][3] * m[2][2] * m[3][0] - m[1][2] * m[2][3] * m[3][0] - 01430 m[1][3] * m[2][0] * m[3][2] + m[1][0] * m[2][3] * m[3][2] + 01431 m[1][2] * m[2][0] * m[3][3] - m[1][0] * m[2][2] * m[3][3]) * scale; 01432 out[1][1] = (m[0][2] * m[2][3] * m[3][0] - m[0][3] * m[2][2] * m[3][0] + 01433 m[0][3] * m[2][0] * m[3][2] - m[0][0] * m[2][3] * m[3][2] - 01434 m[0][2] * m[2][0] * m[3][3] + m[0][0] * m[2][2] * m[3][3]) * scale; 01435 out[1][2] = (m[0][3] * m[1][2] * m[3][0] - m[0][2] * m[1][3] * m[3][0] - 01436 m[0][3] * m[1][0] * m[3][2] + m[0][0] * m[1][3] * m[3][2] + 01437 m[0][2] * m[1][0] * m[3][3] - m[0][0] * m[1][2] * m[3][3]) * scale; 01438 out[1][3] = (m[0][2] * m[1][3] * m[2][0] - m[0][3] * m[1][2] * m[2][0] + 01439 m[0][3] * m[1][0] * m[2][2] - m[0][0] * m[1][3] * m[2][2] - 01440 m[0][2] * m[1][0] * m[2][3] + m[0][0] * m[1][2] * m[2][3]) * scale; 01441 out[2][0] = (m[1][1] * m[2][3] * m[3][0] - m[1][3] * m[2][1] * m[3][0] + 01442 m[1][3] * m[2][0] * m[3][1] - m[1][0] * m[2][3] * m[3][1] - 01443 m[1][1] * m[2][0] * m[3][3] + m[1][0] * m[2][1] * m[3][3]) * scale; 01444 out[2][1] = (m[0][3] * m[2][1] * m[3][0] - m[0][1] * m[2][3] * m[3][0] - 01445 m[0][3] * m[2][0] * m[3][1] + m[0][0] * m[2][3] * m[3][1] + 01446 m[0][1] * m[2][0] * m[3][3] - m[0][0] * m[2][1] * m[3][3]) * scale; 01447 out[2][2] = (m[0][1] * m[1][3] * m[3][0] - m[0][3] * m[1][1] * m[3][0] + 01448 m[0][3] * m[1][0] * m[3][1] - m[0][0] * m[1][3] * m[3][1] - 01449 m[0][1] * m[1][0] * m[3][3] + m[0][0] * m[1][1] * m[3][3]) * scale; 01450 out[2][3] = (m[0][3] * m[1][1] * m[2][0] - m[0][1] * m[1][3] * m[2][0] - 01451 m[0][3] * m[1][0] * m[2][1] + m[0][0] * m[1][3] * m[2][1] + 01452 m[0][1] * m[1][0] * m[2][3] - m[0][0] * m[1][1] * m[2][3]) * scale; 01453 out[3][0] = (m[1][2] * m[2][1] * m[3][0] - m[1][1] * m[2][2] * m[3][0] - 01454 m[1][2] * m[2][0] * m[3][1] + m[1][0] * m[2][2] * m[3][1] + 01455 m[1][1] * m[2][0] * m[3][2] - m[1][0] * m[2][1] * m[3][2]) * scale; 01456 out[3][1] = (m[0][1] * m[2][2] * m[3][0] - m[0][2] * m[2][1] * m[3][0] + 01457 m[0][2] * m[2][0] * m[3][1] - m[0][0] * m[2][2] * m[3][1] - 01458 m[0][1] * m[2][0] * m[3][2] + m[0][0] * m[2][1] * m[3][2]) * scale; 01459 out[3][2] = (m[0][2] * m[1][1] * m[3][0] - m[0][1] * m[1][2] * m[3][0] - 01460 m[0][2] * m[1][0] * m[3][1] + m[0][0] * m[1][2] * m[3][1] + 01461 m[0][1] * m[1][0] * m[3][2] - m[0][0] * m[1][1] * m[3][2]) * scale; 01462 out[3][3] = (m[0][1] * m[1][2] * m[2][0] - m[0][2] * m[1][1] * m[2][0] + 01463 m[0][2] * m[1][0] * m[2][1] - m[0][0] * m[1][2] * m[2][1] - 01464 m[0][1] * m[1][0] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) * scale; 01465 } 01466 #endif 01467 01468 01469 static void 01470 ghid_unproject_to_z_plane (int ex, int ey, Coord pcb_z, Coord *pcb_x, Coord *pcb_y) 01471 { 01472 float mat[2][2]; 01473 float inv_mat[2][2]; 01474 float x, y; 01475 01476 /* 01477 ex = view_matrix[0][0] * vx + 01478 view_matrix[0][1] * vy + 01479 view_matrix[0][2] * vz + 01480 view_matrix[0][3] * 1; 01481 ey = view_matrix[1][0] * vx + 01482 view_matrix[1][1] * vy + 01483 view_matrix[1][2] * vz + 01484 view_matrix[1][3] * 1; 01485 UNKNOWN ez = view_matrix[2][0] * vx + 01486 view_matrix[2][1] * vy + 01487 view_matrix[2][2] * vz + 01488 view_matrix[2][3] * 1; 01489 01490 ex - view_matrix[0][3] * 1 01491 - view_matrix[0][2] * vz 01492 = view_matrix[0][0] * vx + 01493 view_matrix[0][1] * vy; 01494 01495 ey - view_matrix[1][3] * 1 01496 - view_matrix[1][2] * vz 01497 = view_matrix[1][0] * vx + 01498 view_matrix[1][1] * vy; 01499 */ 01500 01501 /* NB: last_modelview_matrix is transposed in memory! */ 01502 x = (float)ex - last_modelview_matrix[3][0] * 1 01503 - last_modelview_matrix[2][0] * pcb_z; 01504 01505 y = (float)ey - last_modelview_matrix[3][1] * 1 01506 - last_modelview_matrix[2][1] * pcb_z; 01507 01508 /* 01509 x = view_matrix[0][0] * vx + 01510 view_matrix[0][1] * vy; 01511 01512 y = view_matrix[1][0] * vx + 01513 view_matrix[1][1] * vy; 01514 01515 [view_matrix[0][0] view_matrix[0][1]] [vx] = [x] 01516 [view_matrix[1][0] view_matrix[1][1]] [vy] [y] 01517 */ 01518 01519 mat[0][0] = last_modelview_matrix[0][0]; 01520 mat[0][1] = last_modelview_matrix[1][0]; 01521 mat[1][0] = last_modelview_matrix[0][1]; 01522 mat[1][1] = last_modelview_matrix[1][1]; 01523 01524 /* if (determinant_2x2 (mat) < 0.00001) */ 01525 /* printf ("Determinant is quite small\n"); */ 01526 01527 invert_2x2 (mat, inv_mat); 01528 01529 *pcb_x = (int)(inv_mat[0][0] * x + inv_mat[0][1] * y); 01530 *pcb_y = (int)(inv_mat[1][0] * x + inv_mat[1][1] * y); 01531 } 01532 01533 01534 bool 01535 ghid_event_to_pcb_coords (int event_x, int event_y, Coord *pcb_x, Coord *pcb_y) 01536 { 01537 ghid_unproject_to_z_plane (event_x, event_y, 0, pcb_x, pcb_y); 01538 01539 return true; 01540 } 01541 01542 bool 01543 ghid_pcb_to_event_coords (Coord pcb_x, Coord pcb_y, int *event_x, int *event_y) 01544 { 01545 /* NB: last_modelview_matrix is transposed in memory */ 01546 float w = last_modelview_matrix[0][3] * (float)pcb_x + 01547 last_modelview_matrix[1][3] * (float)pcb_y + 01548 last_modelview_matrix[2][3] * 0. + 01549 last_modelview_matrix[3][3] * 1.; 01550 01551 *event_x = (last_modelview_matrix[0][0] * (float)pcb_x + 01552 last_modelview_matrix[1][0] * (float)pcb_y + 01553 last_modelview_matrix[2][0] * 0. + 01554 last_modelview_matrix[3][0] * 1.) / w; 01555 *event_y = (last_modelview_matrix[0][1] * (float)pcb_x + 01556 last_modelview_matrix[1][1] * (float)pcb_y + 01557 last_modelview_matrix[2][1] * 0. + 01558 last_modelview_matrix[3][1] * 1.) / w; 01559 01560 return true; 01561 } 01562 01563 void 01564 ghid_view_2d (void *ball, gboolean view_2d, gpointer userdata) 01565 { 01566 global_view_2d = view_2d; 01567 ghid_invalidate_all (); 01568 } 01569 01570 void 01571 ghid_port_rotate (void *ball, float *quarternion, gpointer userdata) 01572 { 01573 #ifdef DEBUG_ROTATE 01574 int row, column; 01575 #endif 01576 01577 build_rotmatrix (view_matrix, quarternion); 01578 01579 #ifdef DEBUG_ROTATE 01580 for (row = 0; row < 4; row++) { 01581 printf ("[ %f", view_matrix[row][0]); 01582 for (column = 1; column < 4; column++) { 01583 printf (",\t%f", view_matrix[row][column]); 01584 } 01585 printf ("\t]\n"); 01586 } 01587 printf ("\n"); 01588 #endif 01589 01590 ghid_invalidate_all (); 01591 } 01592 01593 01594 #define LEAD_USER_WIDTH 0.2 /* millimeters */ 01595 #define LEAD_USER_PERIOD (1000 / 20) /* 20fps (in ms) */ 01596 #define LEAD_USER_VELOCITY 3. /* millimeters per second */ 01597 #define LEAD_USER_ARC_COUNT 3 01598 #define LEAD_USER_ARC_SEPARATION 3. /* millimeters */ 01599 #define LEAD_USER_INITIAL_RADIUS 10. /* millimetres */ 01600 #define LEAD_USER_COLOR_R 1. 01601 #define LEAD_USER_COLOR_G 1. 01602 #define LEAD_USER_COLOR_B 0. 01603 01604 static void 01605 draw_lead_user (render_priv *priv) 01606 { 01607 int i; 01608 double radius = priv->lead_user_radius; 01609 double width = MM_TO_COORD (LEAD_USER_WIDTH); 01610 double separation = MM_TO_COORD (LEAD_USER_ARC_SEPARATION); 01611 01612 if (!priv->lead_user) 01613 return; 01614 01615 glPushAttrib (GL_CURRENT_BIT | GL_COLOR_BUFFER_BIT); 01616 glEnable (GL_COLOR_LOGIC_OP); 01617 glLogicOp (GL_XOR); 01618 glColor3f (LEAD_USER_COLOR_R, LEAD_USER_COLOR_G,LEAD_USER_COLOR_B); 01619 01620 01621 /* arcs at the approrpriate radii */ 01622 01623 for (i = 0; i < LEAD_USER_ARC_COUNT; i++, radius -= separation) 01624 { 01625 if (radius < width) 01626 radius += MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01627 01628 /* Draw an arc at radius */ 01629 hidgl_draw_arc (width, priv->lead_user_x, priv->lead_user_y, 01630 radius, radius, 0, 360, gport->view.coord_per_px); 01631 } 01632 01633 hidgl_flush_triangles (&buffer); 01634 glPopAttrib (); 01635 } 01636 01637 gboolean 01638 lead_user_cb (gpointer data) 01639 { 01640 render_priv *priv = data; 01641 Coord step; 01642 double elapsed_time; 01643 01644 /* Queue a redraw */ 01645 ghid_invalidate_all (); 01646 01647 /* Update radius */ 01648 elapsed_time = g_timer_elapsed (priv->lead_user_timer, NULL); 01649 g_timer_start (priv->lead_user_timer); 01650 01651 step = MM_TO_COORD (LEAD_USER_VELOCITY * elapsed_time); 01652 if (priv->lead_user_radius > step) 01653 priv->lead_user_radius -= step; 01654 else 01655 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01656 01657 return TRUE; 01658 } 01659 01660 void 01661 ghid_lead_user_to_location (Coord x, Coord y) 01662 { 01663 render_priv *priv = gport->render_priv; 01664 01665 ghid_cancel_lead_user (); 01666 01667 priv->lead_user = true; 01668 priv->lead_user_x = x; 01669 priv->lead_user_y = y; 01670 priv->lead_user_radius = MM_TO_COORD (LEAD_USER_INITIAL_RADIUS); 01671 priv->lead_user_timeout = g_timeout_add (LEAD_USER_PERIOD, lead_user_cb, priv); 01672 priv->lead_user_timer = g_timer_new (); 01673 } 01674 01675 void 01676 ghid_cancel_lead_user (void) 01677 { 01678 render_priv *priv = gport->render_priv; 01679 01680 if (priv->lead_user_timeout) 01681 g_source_remove (priv->lead_user_timeout); 01682 01683 if (priv->lead_user_timer) 01684 g_timer_destroy (priv->lead_user_timer); 01685 01686 if (priv->lead_user) 01687 ghid_invalidate_all (); 01688 01689 priv->lead_user_timeout = 0; 01690 priv->lead_user_timer = NULL; 01691 priv->lead_user = false; 01692 }