1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <string.h> /* strlen */
25 #include "render_libart.h"
29 #include "dialibartrenderer.h"
30 #include <libart_lgpl/art_rgb.h>
34 static void clip_region_clear(DiaRenderer
*self
);
35 static void clip_region_add_rect(DiaRenderer
*self
,
38 static void draw_pixel_line(DiaRenderer
*self
,
42 static void draw_pixel_rect(DiaRenderer
*self
,
44 int width
, int height
,
46 static void fill_pixel_rect(DiaRenderer
*self
,
48 int width
, int height
,
50 static void set_size(DiaRenderer
*self
, gpointer window
,
51 int width
, int height
);
52 static void copy_to_window (DiaRenderer
*self
, gpointer window
,
53 int x
, int y
, int width
, int height
);
57 dia_libart_renderer_iface_init (DiaInteractiveRendererInterface
* iface
)
59 iface
->clip_region_clear
= clip_region_clear
;
60 iface
->clip_region_add_rect
= clip_region_add_rect
;
61 iface
->draw_pixel_line
= draw_pixel_line
;
62 iface
->draw_pixel_rect
= draw_pixel_rect
;
63 iface
->fill_pixel_rect
= fill_pixel_rect
;
64 iface
->copy_to_window
= copy_to_window
;
65 iface
->set_size
= set_size
;
70 new_libart_renderer(DiaTransform
*trans
, int interactive
)
72 DiaLibartRenderer
*renderer
;
73 GType renderer_type
= 0;
75 renderer
= g_object_new(DIA_TYPE_LIBART_RENDERER
, NULL
);
76 renderer
->transform
= trans
;
78 if (!DIA_GET_INTERACTIVE_RENDERER_INTERFACE (renderer
))
80 static const GInterfaceInfo irenderer_iface_info
=
82 (GInterfaceInitFunc
) dia_libart_renderer_iface_init
,
83 NULL
, /* iface_finalize */
87 renderer_type
= DIA_TYPE_LIBART_RENDERER
;
88 /* register the interactive renderer interface */
89 g_type_add_interface_static (renderer_type
,
90 DIA_TYPE_INTERACTIVE_RENDERER_INTERFACE
,
91 &irenderer_iface_info
);
93 renderer
->parent_instance
.is_interactive
= interactive
;
95 return DIA_RENDERER (renderer
);
99 set_size(DiaRenderer
*self
, gpointer window
,
100 int width
, int height
)
102 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
105 if ( (renderer
->pixel_width
==width
) &&
106 (renderer
->pixel_height
==height
) )
109 if (renderer
->rgb_buffer
!= NULL
) {
110 g_free(renderer
->rgb_buffer
);
113 renderer
->rgb_buffer
= g_new (guint8
, width
* height
* 3);
114 for (i
=0;i
<width
* height
* 3;i
++)
115 renderer
->rgb_buffer
[i
] = 0xff;
116 renderer
->pixel_width
= width
;
117 renderer
->pixel_height
= height
;
121 copy_to_window (DiaRenderer
*self
, gpointer window
,
122 int x
, int y
, int width
, int height
)
125 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
128 copy_gc
= gdk_gc_new(GDK_WINDOW(window
));
130 w
= renderer
->pixel_width
;
132 gdk_draw_rgb_image(window
,
137 renderer
->rgb_buffer
+x
*3+y
*3*w
,
139 g_object_unref(copy_gc
);
143 clip_region_clear(DiaRenderer
*self
)
145 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
147 renderer
->clip_rect_empty
= 1;
148 renderer
->clip_rect
.top
= 0;
149 renderer
->clip_rect
.bottom
= 0;
150 renderer
->clip_rect
.left
= 0;
151 renderer
->clip_rect
.right
= 0;
155 clip_region_add_rect(DiaRenderer
*self
,
158 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
163 dia_transform_coords(renderer
->transform
, rect
->left
, rect
->top
, &x1
, &y1
);
164 dia_transform_coords(renderer
->transform
, rect
->right
, rect
->bottom
, &x2
, &y2
);
170 if (x2
>= renderer
->pixel_width
)
171 x2
= renderer
->pixel_width
- 1;
172 if (y2
>= renderer
->pixel_height
)
173 y2
= renderer
->pixel_height
- 1;
180 if (renderer
->clip_rect_empty
) {
181 renderer
->clip_rect
= r
;
182 renderer
->clip_rect_empty
= 0;
184 int_rectangle_union(&renderer
->clip_rect
, &r
);
190 * This code is used to draw pixel based stuff in the RGB buffer.
191 * This code is *NOT* as efficient as it could be!
194 /* All lines and rectangles specifies the coordinates inclusive.
195 * This means that a line from x1 to x2 renders both points.
196 * If a length is specified the line x to (inclusive) x+width is rendered.
198 * The boundaries of the clipping rectangle *are* rendered.
199 * so min=5 and max=10 means point 5 and 10 might be rendered to.
202 /* If the start-end interval is totaly outside the min-max,
203 then the returned clipped values can have len<0! */
204 #define CLIP_1D_LEN(min, max, start, len) \
205 if ((start) < (min)) { \
206 (len) -= (min) - (start); \
209 if ((start)+(len) > (max)) { \
210 (len) = (max) - (start); \
213 /* Does no clipping! */
215 draw_hline(DiaRenderer
*self
,
216 int x
, int y
, int length
,
217 guint8 r
, guint8 g
, guint8 b
)
219 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
223 stride
= renderer
->pixel_width
*3;
224 ptr
= renderer
->rgb_buffer
+ x
*3 + y
*stride
;
226 art_rgb_fill_run(ptr
, r
, g
, b
, length
+1);
229 /* Does no clipping! */
231 draw_vline(DiaRenderer
*self
,
232 int x
, int y
, int height
,
233 guint8 r
, guint8 g
, guint8 b
)
235 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
239 stride
= renderer
->pixel_width
*3;
240 ptr
= renderer
->rgb_buffer
+ x
*3 + y
*stride
;
252 draw_pixel_line(DiaRenderer
*self
,
257 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
264 int dx
, dy
, adx
, ady
;
266 int incx_ptr
, incy_ptr
;
268 IntRectangle
*clip_rect
;
272 g
= color
->green
*0xff;
273 b
= color
->blue
*0xff;
275 if (y1
==y2
) { /* Horizontal line */
278 CLIP_1D_LEN(renderer
->clip_rect
.left
, renderer
->clip_rect
.right
, start
, len
);
281 if ( (y1
>=renderer
->clip_rect
.top
) &&
282 (y1
<=renderer
->clip_rect
.bottom
) ) {
283 draw_hline(self
, start
, y1
, len
, r
, g
, b
);
288 if (x1
==x2
) { /* Vertical line */
291 CLIP_1D_LEN(renderer
->clip_rect
.top
, renderer
->clip_rect
.bottom
, start
, len
);
294 if ( (x1
>=renderer
->clip_rect
.left
) &&
295 (x1
<=renderer
->clip_rect
.right
) ) {
296 draw_vline(self
, x1
, start
, len
, r
, g
, b
);
301 /* Ugh, kill me slowly for writing this line-drawer.
302 * It is actually a standard bresenham, but not very optimized.
303 * It is also not very well tested.
306 stride
= renderer
->pixel_width
*3;
307 clip_rect
= &renderer
->clip_rect
;
311 adx
= (dx
>=0)?dx
:-dx
;
312 ady
= (dy
>=0)?dy
:-dy
;
315 ptr
= renderer
->rgb_buffer
+ x
*3 + y
*stride
;
317 if (adx
>=ady
) { /* x-major */
334 for (i
=0;i
<=adx
;i
++) {
335 /* Amazing... He does the clipping in the inner loop!
336 It must be horribly inefficient! */
337 if ( (x
>=clip_rect
->left
) &&
338 (x
<=clip_rect
->right
) &&
339 (y
>=clip_rect
->top
) &&
340 (y
<=clip_rect
->bottom
) ) {
348 if ((frac_pos
> 2*adx
) || ((dy
>0)&&(frac_pos
== 2*adx
))) {
354 } else { /* y-major */
371 for (i
=0;i
<=ady
;i
++) {
372 /* Amazing... He does the clipping in the inner loop!
373 It must be horribly inefficient! */
374 if ( (x
>=clip_rect
->left
) &&
375 (x
<=clip_rect
->right
) &&
376 (y
>=clip_rect
->top
) &&
377 (y
<=clip_rect
->bottom
) ) {
385 if ((frac_pos
> 2*ady
) || ((dx
>0)&&(frac_pos
== 2*ady
))) {
395 draw_pixel_rect(DiaRenderer
*self
,
397 int width
, int height
,
400 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
406 g
= color
->green
*0xff;
407 b
= color
->blue
*0xff;
409 stride
= renderer
->pixel_width
*3;
414 CLIP_1D_LEN(renderer
->clip_rect
.left
, renderer
->clip_rect
.right
, start
, len
);
417 if ( (y
>=renderer
->clip_rect
.top
) &&
418 (y
<=renderer
->clip_rect
.bottom
) ) {
419 draw_hline(self
, start
, y
, len
, r
, g
, b
);
423 if ( (y
+height
>=renderer
->clip_rect
.top
) &&
424 (y
+height
<=renderer
->clip_rect
.bottom
) ) {
425 draw_hline(self
, start
, y
+height
, len
, r
, g
, b
);
431 CLIP_1D_LEN(renderer
->clip_rect
.top
, renderer
->clip_rect
.bottom
, start
, len
);
434 if ( (x
>=renderer
->clip_rect
.left
) &&
435 (x
<renderer
->clip_rect
.right
) ) {
436 draw_vline(self
, x
, start
, len
, r
, g
, b
);
440 if ( (x
+width
>=renderer
->clip_rect
.left
) &&
441 (x
+width
<renderer
->clip_rect
.right
) ) {
442 draw_vline(self
, x
+width
, start
, len
, r
, g
, b
);
447 fill_pixel_rect(DiaRenderer
*self
,
449 int width
, int height
,
452 DiaLibartRenderer
*renderer
= DIA_LIBART_RENDERER (self
);
459 CLIP_1D_LEN(renderer
->clip_rect
.left
, renderer
->clip_rect
.right
, x
, width
);
463 CLIP_1D_LEN(renderer
->clip_rect
.top
, renderer
->clip_rect
.bottom
, y
, height
);
468 g
= color
->green
*0xff;
469 b
= color
->blue
*0xff;
471 stride
= renderer
->pixel_width
*3;
472 ptr
= renderer
->rgb_buffer
+ x
*3 + y
*stride
;
473 for (i
=0;i
<=height
;i
++) {
474 art_rgb_fill_run(ptr
, r
, g
, b
, width
+1);
482 new_libart_renderer(DiaTransform
*transform
, int interactive
)