2 * gEDA - GNU Electronic Design Automation
4 * render.c -- this file is a part of gerbv.
6 * Copyright (C) 2007 Stuart Brorson (SDB@cloud9.net)
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
42 #include <libgen.h> /* dirname */
48 #include "gerb_error.h"
49 #include "gerb_stats.h"
50 #include "drill_stats.h"
52 #ifdef RENDER_USING_GDK
56 #include <cairo-xlib.h>
60 #include "gerbv_screen.h"
65 #include "callbacks.h"
66 #include "interface.h"
71 #include "exportimage.h"
72 #endif /* EXPORT_PNG */
74 #define dprintf if(DEBUG) printf
76 /**Global variable to keep track of what's happening on the screen.
77 Declared extern in gerbv_screen.h
79 extern gerbv_screen_t screen
;
81 gerbv_render_info_t screenRenderInfo
;
84 render_zoom_display (gint zoomType
, gdouble scaleFactor
, gdouble mouseX
, gdouble mouseY
) {
85 double us_midx
, us_midy
; /* unscaled translation for screen center */
86 int half_w
, half_h
; /* cache for half window dimensions */
87 gdouble mouseCoordinateX
= 0.0;
88 gdouble mouseCoordinateY
= 0.0;
89 double oldWidth
, oldHeight
;
91 half_w
= screenRenderInfo
.displayWidth
/ 2;
92 half_h
= screenRenderInfo
.displayHeight
/ 2;
94 oldWidth
= screenRenderInfo
.displayWidth
/ screenRenderInfo
.scaleFactor
;
95 oldHeight
= screenRenderInfo
.displayHeight
/ screenRenderInfo
.scaleFactor
;
97 if (zoomType
== ZOOM_IN_CMOUSE
|| zoomType
== ZOOM_OUT_CMOUSE
) {
98 /* calculate what user coordinate the mouse is pointing at */
99 mouseCoordinateX
= mouseX
/ screenRenderInfo
.scaleFactor
+ screenRenderInfo
.lowerLeftX
;
100 mouseCoordinateY
= (screenRenderInfo
.displayHeight
- mouseY
) /
101 screenRenderInfo
.scaleFactor
+ screenRenderInfo
.lowerLeftY
;
104 us_midx
= screenRenderInfo
.lowerLeftX
+ (screenRenderInfo
.displayWidth
/ 2.0 )/
105 screenRenderInfo
.scaleFactor
;
106 us_midy
= screenRenderInfo
.lowerLeftY
+ (screenRenderInfo
.displayHeight
/ 2.0 )/
107 screenRenderInfo
.scaleFactor
;
110 case ZOOM_IN
: /* Zoom In */
111 case ZOOM_IN_CMOUSE
: /* Zoom In Around Mouse Pointer */
112 screenRenderInfo
.scaleFactor
+= screenRenderInfo
.scaleFactor
/3;
113 screenRenderInfo
.lowerLeftX
+= (oldWidth
- (screenRenderInfo
.displayWidth
/
114 screenRenderInfo
.scaleFactor
)) / 2.0;
115 screenRenderInfo
.lowerLeftY
+= (oldHeight
- (screenRenderInfo
.displayHeight
/
116 screenRenderInfo
.scaleFactor
)) / 2.0;
118 case ZOOM_OUT
: /* Zoom Out */
119 case ZOOM_OUT_CMOUSE
: /* Zoom Out Around Mouse Pointer */
120 if (screenRenderInfo
.scaleFactor
> 10) {
121 screenRenderInfo
.scaleFactor
-= screenRenderInfo
.scaleFactor
/3;
122 screenRenderInfo
.lowerLeftX
+= (oldWidth
- (screenRenderInfo
.displayWidth
/
123 screenRenderInfo
.scaleFactor
)) / 2.0;
124 screenRenderInfo
.lowerLeftY
+= (oldHeight
- (screenRenderInfo
.displayHeight
/
125 screenRenderInfo
.scaleFactor
)) / 2.0;
128 case ZOOM_FIT
: /* Zoom Fit */
129 render_zoom_to_fit_display (&screenRenderInfo
);
131 case ZOOM_SET
: /*explicit scale set by user */
132 screenRenderInfo
.scaleFactor
= scaleFactor
;
133 screenRenderInfo
.lowerLeftX
+= (oldWidth
- (screenRenderInfo
.displayWidth
/
134 screenRenderInfo
.scaleFactor
)) / 2.0;
135 screenRenderInfo
.lowerLeftY
+= (oldHeight
- (screenRenderInfo
.displayHeight
/
136 screenRenderInfo
.scaleFactor
)) / 2.0;
139 GERB_MESSAGE("Illegal zoom direction %d\n", zoomType
);
142 if (zoomType
== ZOOM_IN_CMOUSE
|| zoomType
== ZOOM_OUT_CMOUSE
) {
143 /* make sure the mouse is still pointing at the point calculated earlier */
144 screenRenderInfo
.lowerLeftX
= mouseCoordinateX
- mouseX
/ screenRenderInfo
.scaleFactor
;
145 screenRenderInfo
.lowerLeftY
= mouseCoordinateY
- (screenRenderInfo
.displayHeight
- mouseY
) /
146 screenRenderInfo
.scaleFactor
;
149 render_refresh_rendered_image_on_screen();
154 /* --------------------------------------------------------- */
155 /** Will determine the outline of the zoomed regions.
156 * In case region to be zoomed is too small (which correspondes
157 * e.g. to a double click) it is interpreted as a right-click
158 * and will be used to identify a part from the CURRENT selection,
159 * which is drawn on screen*/
161 render_calculate_zoom_from_outline(GtkWidget
*widget
, GdkEventButton
*event
)
163 int x1
, y1
, x2
, y2
, dx
, dy
; /* Zoom outline (UR and LL corners) */
164 double centerPointX
, centerPointY
;
165 int half_x
, half_y
; /* cache for half window dimensions */
167 x1
= MIN(screen
.start_x
, event
->x
);
168 y1
= MIN(screen
.start_y
, event
->y
);
169 x2
= MAX(screen
.start_x
, event
->x
);
170 y2
= MAX(screen
.start_y
, event
->y
);
174 if ((dx
>= 4) && (dy
>= 4)) {
175 if (screen
.centered_outline_zoom
) {
176 /* Centered outline mode */
177 x1
= screen
.start_x
- dx
;
178 y1
= screen
.start_y
- dy
;
185 centerPointX
= half_x
/screenRenderInfo
.scaleFactor
+ screenRenderInfo
.lowerLeftX
;
186 centerPointY
= (screenRenderInfo
.displayHeight
- half_y
)/screenRenderInfo
.scaleFactor
+
187 screenRenderInfo
.lowerLeftY
;
189 screenRenderInfo
.scaleFactor
*= MIN(((double)screenRenderInfo
.displayWidth
/ dx
),
190 ((double)screenRenderInfo
.displayHeight
/ dy
));
191 screenRenderInfo
.lowerLeftX
= centerPointX
- (screenRenderInfo
.displayWidth
/
192 2.0 / screenRenderInfo
.scaleFactor
);
193 screenRenderInfo
.lowerLeftY
= centerPointY
- (screenRenderInfo
.displayHeight
/
194 2.0 / screenRenderInfo
.scaleFactor
);
196 render_refresh_rendered_image_on_screen();
199 /* --------------------------------------------------------- */
201 render_draw_zoom_outline(gboolean centered
)
205 GdkGCValuesMask values_mask
;
206 gint x1
, y1
, x2
, y2
, dx
, dy
;
208 memset(&values
, 0, sizeof(values
));
209 values
.function
= GDK_XOR
;
210 values
.foreground
= screen
.zoom_outline_color
;
211 values_mask
= GDK_GC_FUNCTION
| GDK_GC_FOREGROUND
;
212 gc
= gdk_gc_new_with_values(screen
.drawing_area
->window
, &values
, values_mask
);
214 x1
= MIN(screen
.start_x
, screen
.last_x
);
215 y1
= MIN(screen
.start_y
, screen
.last_y
);
216 x2
= MAX(screen
.start_x
, screen
.last_x
);
217 y2
= MAX(screen
.start_y
, screen
.last_y
);
222 /* Centered outline mode */
223 x1
= screen
.start_x
- dx
;
224 y1
= screen
.start_y
- dy
;
231 gdk_draw_rectangle(screen
.drawing_area
->window
, gc
, FALSE
, x1
, y1
, dx
, dy
);
234 /* Draw actual zoom area in dashed lines */
235 memset(&values
, 0, sizeof(values
));
236 values
.function
= GDK_XOR
;
237 values
.foreground
= screen
.zoom_outline_color
;
238 values
.line_style
= GDK_LINE_ON_OFF_DASH
;
239 values_mask
= GDK_GC_FUNCTION
| GDK_GC_FOREGROUND
| GDK_GC_LINE_STYLE
;
240 gc
= gdk_gc_new_with_values(screen
.drawing_area
->window
, &values
,
243 if ((dy
== 0) || ((double)dx
/dy
> (double)screen
.drawing_area
->allocation
.width
/
244 screen
.drawing_area
->allocation
.height
)) {
245 dy
= dx
* (double)screen
.drawing_area
->allocation
.height
/
246 screen
.drawing_area
->allocation
.width
;
249 dx
= dy
* (double)screen
.drawing_area
->allocation
.width
/
250 screen
.drawing_area
->allocation
.height
;
253 gdk_draw_rectangle(screen
.drawing_area
->window
, gc
, FALSE
, (x1
+x2
-dx
)/2,
254 (y1
+y2
-dy
)/2, dx
, dy
);
260 /** Displays a measured distance graphically on screen and in statusbar.
261 activated when using SHIFT and mouse dragged to measure distances\n
262 under win32 graphical annotations are currently disabled (GTK 2.47)*/
264 render_draw_measure_distance(void)
266 #if !defined (__MINGW32__)
270 GdkGCValuesMask values_mask
;
274 double delta
, dx
, dy
;
276 #if !defined (__MINGW32__) /*taken out because of different drawing behaviour under win32 resulting in a smear */
277 memset(&values
, 0, sizeof(values
));
278 values
.function
= GDK_XOR
;
279 values
.foreground
= screen
.dist_measure_color
;
280 values_mask
= GDK_GC_FUNCTION
| GDK_GC_FOREGROUND
;
281 gc
= gdk_gc_new_with_values(screen
.drawing_area
->window
, &values
,
283 font
= gdk_font_load(setup
.dist_fontname
);
285 x1
= MIN(screen
.start_x
, screen
.last_x
);
286 y1
= MIN(screen
.start_y
, screen
.last_y
);
287 x2
= MAX(screen
.start_x
, screen
.last_x
);
288 y2
= MAX(screen
.start_y
, screen
.last_y
);
290 dx
= (x2
- x1
)/ screenRenderInfo
.scaleFactor
;
291 dy
= (y2
- y1
)/ screenRenderInfo
.scaleFactor
;
292 delta
= sqrt(dx
*dx
+ dy
*dy
); /* Pythagoras */
294 #if !defined (__MINGW32__)
295 gdk_draw_line(screen
.drawing_area
->window
, gc
, screen
.start_x
,
296 screen
.start_y
, screen
.last_x
, screen
.last_y
);
298 GERB_MESSAGE("Failed to load font '%s'\n", setup
.dist_fontname
);
305 if (screen
.unit
== GERBV_MILS
) {
306 snprintf(screen
.statusbar
.diststr
, MAX_DISTLEN
,
307 "Measured distance: %7.1f mils (%7.1f X, %7.1f Y)",
308 COORD2MILS(delta
), COORD2MILS(dx
), COORD2MILS(dy
));
310 else if (screen
.unit
== GERBV_MMS
) {
311 snprintf(screen
.statusbar
.diststr
, MAX_DISTLEN
,
312 "Measured distance: %7.1f mms (%7.1f X, %7.1f Y)",
313 COORD2MMS(delta
), COORD2MMS(dx
), COORD2MMS(dy
));
316 snprintf(screen
.statusbar
.diststr
, MAX_DISTLEN
,
317 "Measured distance: %3.4f inches (%3.4f X, %3.4f Y)",
318 COORD2MILS(delta
) / 1000.0, COORD2MILS(dx
) / 1000.0,
319 COORD2MILS(dy
) / 1000.0);
321 callbacks_update_statusbar();
323 #if !defined (__MINGW32__)
327 } /* draw_measure_distance */
330 render_translate_to_fit_display (gerbv_render_info_t
*renderInfo
) {
331 double x1
=HUGE_VAL
,y1
=HUGE_VAL
;
333 gerb_image_info_t
*info
;
335 for(i
= 0; i
< MAX_FILES
; i
++) {
336 if ((screen
.file
[i
]) && (screen
.file
[i
]->isVisible
)){
337 info
= screen
.file
[i
]->image
->info
;
339 /* cairo info already has offset calculated into min/max */
340 x1
= MIN(x1
, info
->min_x
);
341 y1
= MIN(y1
, info
->min_y
);
344 renderInfo
->lowerLeftX
= x1
;
345 renderInfo
->lowerLeftY
= y1
;
348 /* ------------------------------------------------------------------ */
350 render_zoom_to_fit_display (gerbv_render_info_t
*renderInfo
) {
351 double max_width
= LONG_MIN
, max_height
= LONG_MIN
,x1
=HUGE_VAL
,y1
=HUGE_VAL
,
352 x2
=-HUGE_VAL
,y2
=-HUGE_VAL
;
353 double x_scale
, y_scale
;
355 gerb_image_info_t
*info
;
357 for(i
= 0; i
< MAX_FILES
; i
++) {
358 if ((screen
.file
[i
]) && (screen
.file
[i
]->isVisible
)){
359 info
= screen
.file
[i
]->image
->info
;
361 * Find the biggest image and use as a size reference
363 #ifdef RENDER_USING_GDK
364 x1
= MIN(x1
, info
->min_x
+ info
->offsetA
);
365 y1
= MIN(y1
, info
->min_y
+ info
->offsetB
);
366 x2
= MAX(x2
, info
->max_x
+ info
->offsetA
);
367 y2
= MAX(y2
, info
->max_y
+ info
->offsetB
);
369 /* cairo info already has offset calculated into min/max */
370 x1
= MIN(x1
, info
->min_x
);
371 y1
= MIN(y1
, info
->min_y
);
372 x2
= MAX(x2
, info
->max_x
);
373 y2
= MAX(y2
, info
->max_y
);
378 /* add in a 5% buffer around the drawing */
379 max_width
= (x2
- x1
)*1.05;
380 max_height
= (y2
- y1
)*1.05;
382 /* if the values aren't sane (probably we have no models loaded), then
383 put in some defaults */
384 if ((max_width
< 0.01) || (max_height
< 0.01)) {
385 renderInfo
->lowerLeftX
= 0.0;
386 renderInfo
->lowerLeftY
= 0.0;
387 renderInfo
->scaleFactor
= 50;
391 * Calculate scale for both x axis and y axis
393 x_scale
= renderInfo
->displayWidth
/ max_width
;
394 y_scale
= renderInfo
->displayHeight
/ max_height
;
397 * Take the scale that fits both directions with some extra checks
399 renderInfo
->scaleFactor
= MIN(x_scale
, y_scale
);
400 if (renderInfo
->scaleFactor
< 1)
401 renderInfo
->scaleFactor
= 1;
403 renderInfo
->lowerLeftX
= ((x1
+ x2
) / 2.0) -
404 ((double) renderInfo
->displayWidth
/ 2.0 / renderInfo
->scaleFactor
);
405 renderInfo
->lowerLeftY
= ((y1
+ y2
) / 2.0) -
406 ((double) renderInfo
->displayHeight
/ 2.0 / renderInfo
->scaleFactor
);
410 void render_refresh_rendered_image_on_screen (void) {
411 #ifdef RENDER_USING_GDK
414 dprintf("----> Entering redraw_pixmap...\n");
416 window
= gtk_widget_get_parent_window(screen
.drawing_area
);
417 /* This might be lengthy, show that we're busy by changing the pointer */
421 cursor
= gdk_cursor_new(GDK_WATCH
);
422 gdk_window_set_cursor(window
, cursor
);
423 gdk_cursor_destroy(cursor
);
427 gdk_pixmap_unref(screen
.pixmap
);
428 screen
.pixmap
= gdk_pixmap_new(screen
.drawing_area
->window
, screenRenderInfo
.displayWidth
,
429 screenRenderInfo
.displayHeight
, -1);
430 render_to_pixmap_using_gdk (screen
.pixmap
, &screenRenderInfo
);
432 /* Return default pointer shape */
434 gdk_window_set_cursor(window
, GERBV_DEF_CURSOR
);
436 dprintf("<---- leaving redraw_pixmap.\n");
440 GTimer* profileTimer = g_timer_new ();
442 dprintf(" .... Now try rendering the drawing using cairo .... \n");
445 * This now allows drawing several layers on top of each other.
446 * Higher layer numbers have higher priority in the Z-order.
448 for(i
= 0; i
< MAX_FILES
; i
++) {
449 if (screen
.file
[i
]) {
452 if (screen
.file
[i
]->privateRenderData
)
453 cairo_surface_destroy ((cairo_surface_t
*) screen
.file
[i
]->privateRenderData
);
455 /* save a little time by rendering the bottom layer without alpha, since
456 it doesn't need it for compositing */
458 screen
.file
[i
]->privateRenderData
=
459 (gpointer
) cairo_surface_create_similar ((cairo_surface_t
*)screen
.windowSurface
,
460 CAIRO_CONTENT_COLOR
, screenRenderInfo
.displayWidth
,
461 screenRenderInfo
.displayHeight
);
464 screen
.file
[i
]->privateRenderData
=
465 (gpointer
) cairo_surface_create_similar ((cairo_surface_t
*)screen
.windowSurface
,
466 CAIRO_CONTENT_COLOR_ALPHA
, screenRenderInfo
.displayWidth
,
467 screenRenderInfo
.displayHeight
);
469 cr
= cairo_create(screen
.file
[i
]->privateRenderData
);
470 render_layer_to_cairo_target (cr
, screen
.file
[i
], &screenRenderInfo
);
471 dprintf(" .... calling render_image_to_cairo_target on layer %d...\n", i
);
475 render_recreate_composite_surface ();
478 g_timer_stop (profileTimer);
481 gdouble timerSeconds = g_timer_elapsed (profileTimer, &timerMicros);
482 g_warning ("Timer: %f seconds, %ld micros\n",timerSeconds,timerMicros);
483 g_timer_destroy (profileTimer);
488 callbacks_force_expose_event_for_screen();
491 #ifndef RENDER_USING_GDK
492 void render_all_layers_to_cairo_target_for_vector_output (cairo_t
*cr
, gerbv_render_info_t
*renderInfo
) {
495 /* don't paint background for vector output, since it isn't needed */
496 for(i
= 0; i
< MAX_FILES
; i
++) {
497 if (screen
.file
[i
] && screen
.file
[i
]->isVisible
) {
498 /* since compositing layers properly destroys the vector data,
499 we just draw right on top of the last layer (producing errors
500 in cases where something was drawn with the "clear" aperture state */
501 render_layer_to_cairo_target (cr
, screen
.file
[i
], renderInfo
);
506 void render_all_layers_to_cairo_target (cairo_t
*cr
, gerbv_render_info_t
*renderInfo
) {
508 /* fill the background with the appropriate color */
509 cairo_set_source_rgba (cr
, (double) screen
.background
.red
/G_MAXUINT16
,
510 (double) screen
.background
.green
/G_MAXUINT16
,
511 (double) screen
.background
.blue
/G_MAXUINT16
, 1);
514 for(i
= 0; i
< MAX_FILES
; i
++) {
515 if (screen
.file
[i
] && screen
.file
[i
]->isVisible
) {
516 cairo_push_group (cr
);
517 render_layer_to_cairo_target (cr
, screen
.file
[i
], renderInfo
);
518 cairo_pop_group_to_source (cr
);
519 cairo_paint_with_alpha (cr
, screen
.file
[i
]->alpha
);
524 void render_layer_to_cairo_target (cairo_t
*cr
, gerbv_fileinfo_t
*fileInfo
,
525 gerbv_render_info_t
*renderInfo
) {
526 gdouble translateX
, translateY
;
528 translateX
= (renderInfo
->lowerLeftX
* renderInfo
->scaleFactor
);
529 translateY
= (renderInfo
->lowerLeftY
* renderInfo
->scaleFactor
);
531 if (renderInfo
->renderType
== 0) {
532 cairo_set_tolerance (cr
, 1.5);
533 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_DEFAULT
);
535 else if (renderInfo
->renderType
== 1) {
536 cairo_set_tolerance (cr
, 2);
537 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_NONE
);
539 else if (renderInfo
->renderType
== 2) {
540 cairo_set_tolerance (cr
, 1);
541 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_DEFAULT
);
544 /* translate the draw area before drawing. We must translate the whole
545 drawing down an additional displayHeight to account for the negative
547 cairo_translate (cr
, -translateX
, translateY
+ renderInfo
->displayHeight
);
548 /* scale the drawing by the specified scale factor (inverting y since
549 cairo y axis points down) */
550 cairo_scale (cr
, renderInfo
->scaleFactor
, -renderInfo
->scaleFactor
);
552 cairo_set_source_rgba (cr
, (double) fileInfo
->color
.red
/G_MAXUINT16
,
553 (double) fileInfo
->color
.green
/G_MAXUINT16
,
554 (double) fileInfo
->color
.blue
/G_MAXUINT16
, 1);
556 draw_image_to_cairo_target (cr
, fileInfo
->image
);
559 void render_recreate_composite_surface () {
562 if (screen
.bufferSurface
) {
563 cairo_surface_destroy (screen
.bufferSurface
);
564 screen
.bufferSurface
= NULL
;
566 if (!screen
.windowSurface
)
569 screen
.bufferSurface
= cairo_surface_create_similar ((cairo_surface_t
*)screen
.windowSurface
,
570 CAIRO_CONTENT_COLOR
, screenRenderInfo
.displayWidth
,
571 screenRenderInfo
.displayHeight
);
573 cairo_t
*cr
= cairo_create(screen
.bufferSurface
);
575 for(i
= 0; i
< MAX_FILES
; i
++) {
576 if (screen
.file
[i
] && screen
.file
[i
]->isVisible
) {
577 cairo_set_source_surface (cr
, (cairo_surface_t
*) screen
.file
[i
]->privateRenderData
,
579 /* ignore alpha if we are in high-speed render mode */
580 if (((double) screen
.file
[i
]->alpha
< 65535)&&(screenRenderInfo
.renderType
!= 1)) {
581 cairo_paint_with_alpha(cr
,(double) screen
.file
[i
]->alpha
/G_MAXUINT16
);
591 void render_project_to_cairo_target (cairo_t
*cr
) {
592 /* fill the background with the appropriate color */
593 cairo_set_source_rgba (cr
, (double) screen
.background
.red
/G_MAXUINT16
,
594 (double) screen
.background
.green
/G_MAXUINT16
,
595 (double) screen
.background
.blue
/G_MAXUINT16
, 1);
598 cairo_set_source_surface (cr
, (cairo_surface_t
*) screen
.bufferSurface
, 0 , 0);
604 #ifdef RENDER_USING_GDK
606 render_to_pixmap_using_gdk (GdkPixmap
*pixmap
, gerbv_render_info_t
*renderInfo
){
607 GdkGC
*gc
= gdk_gc_new(pixmap
);
608 GdkPixmap
*colorStamp
, *clipmask
;
612 * Remove old pixmap, allocate a new one, draw the background.
615 gdk_gc_set_foreground(gc
, &screen
.background
);
616 gdk_draw_rectangle(pixmap
, gc
, TRUE
, 0, 0, -1, -1);
619 * Allocate the pixmap and the clipmask (a one pixel pixmap)
621 colorStamp
= gdk_pixmap_new(pixmap
, renderInfo
->displayWidth
,
622 renderInfo
->displayHeight
, -1);
623 clipmask
= gdk_pixmap_new(NULL
, renderInfo
->displayWidth
,
624 renderInfo
->displayHeight
, 1);
626 if (renderInfo
->renderType
== 0) {
627 gdk_gc_set_function(gc
, GDK_COPY
);
629 else if (renderInfo
->renderType
== 1) {
630 gdk_gc_set_function(gc
, GDK_AND
);
632 else if (renderInfo
->renderType
== 2) {
633 gdk_gc_set_function(gc
, GDK_OR
);
635 else if (renderInfo
->renderType
== 3) {
636 gdk_gc_set_function(gc
, GDK_XOR
);
639 gdk_gc_set_function(gc
, GDK_COPY
);
643 * This now allows drawing several layers on top of each other.
644 * Higher layer numbers have higher priority in the Z-order.
646 for(i
= 0; i
< MAX_FILES
; i
++) {
647 if (screen
.file
[i
] && screen
.file
[i
]->isVisible
) {
648 enum polarity_t polarity
;
650 if (screen
.file
[i
]->inverted
) {
651 if (screen
.file
[i
]->image
->info
->polarity
== POSITIVE
)
656 polarity
= screen
.file
[i
]->image
->info
->polarity
;
660 * Fill up image with all the foreground color. Excess pixels
661 * will be removed by clipmask.
663 gdk_gc_set_foreground(gc
, &screen
.file
[i
]->color
);
664 gdk_draw_rectangle(colorStamp
, gc
, TRUE
, 0, 0, -1, -1);
667 * Translation is to get it inside the allocated pixmap,
668 * which is not always centered perfectly for GTK/X.
670 dprintf(" .... calling image2pixmap on image %d...\n", i
);
671 image2pixmap(&clipmask
, screen
.file
[i
]->image
,
672 renderInfo
->scaleFactor
, -(renderInfo
->lowerLeftX
* renderInfo
->scaleFactor
),
673 (renderInfo
->lowerLeftY
* renderInfo
->scaleFactor
) + renderInfo
->displayHeight
,
677 * Set clipmask and draw the clipped out image onto the
678 * screen pixmap. Afterwards we remove the clipmask, else
679 * it will screw things up when run this loop again.
681 gdk_gc_set_clip_mask(gc
, clipmask
);
682 gdk_gc_set_clip_origin(gc
, 0, 0);
683 gdk_draw_drawable(pixmap
, gc
, colorStamp
, 0, 0, 0, 0, -1, -1);
684 gdk_gc_set_clip_mask(gc
, NULL
);
688 gdk_pixmap_unref(colorStamp
);
689 gdk_pixmap_unref(clipmask
);
694 /* ------------------------------------------------------------------ */
695 /* Fill out the gerber statistics table */
697 generate_gerber_analysis(void)
701 gerb_stats_t
*instats
;
703 stats
= gerb_stats_new();
705 /* Loop through open layers and compile statistics */
706 for(i
= 0; i
< MAX_FILES
; i
++) {
707 if (screen
.file
[i
] &&
708 screen
.file
[i
]->isVisible
&&
709 (screen
.file
[i
]->image
->layertype
== GERBER
) ) {
710 instats
= screen
.file
[i
]->image
->gerb_stats
;
711 gerb_stats_add_layer(stats
, instats
, i
+1);
719 /* ------------------------------------------------------------------ */
720 /* Fill out the drill file statistics table */
722 generate_drill_analysis(void)
725 drill_stats_t
*stats
;
726 drill_stats_t
*instats
;
728 stats
= drill_stats_new();
730 /* Loop through open layers and compile statistics */
731 for(i
= 0; i
< MAX_FILES
; i
++) {
732 if (screen
.file
[i
] &&
733 screen
.file
[i
]->isVisible
&&
734 (screen
.file
[i
]->image
->layertype
== DRILL
) ) {
735 instats
= screen
.file
[i
]->image
->drill_stats
;
736 /* add this batch of stats. Send the layer
737 * index for error reporting */
738 drill_stats_add_layer(stats
, instats
, i
+1);