2 * Copyright (c) 2007, 2008, 2009, Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <glib/gi18n.h>
19 #include <glib/gstdio.h>
25 #include "caveobject.h"
27 #include "c64_gfx.h" /* char c64_gfx[] with (almost) original graphics */
31 #include "c64_png_colors.h"
33 static GdkPixbuf
*cells_pb
[NUM_OF_CELLS
];
34 static GdkPixbuf
*combo_pb
[NUM_OF_CELLS
];
36 static GdkPixmap
*cells_game
[NUM_OF_CELLS
*3], *cells_editor
[NUM_OF_CELLS
*3];
37 int gd_cell_size_game
, gd_cell_size_editor
;
39 GdkPixbuf
*gd_pixbuf_for_builtin_theme
; /* this stores a player image, which is the pixbuf for the settings window */
44 static GdColor color0
, color1
, color2
, color3
, color4
, color5
; /* currently used cell colors */
45 static guint8
*c64_custom_gfx
=NULL
;
46 static gboolean using_png_gfx
;
48 /* to be called at application start. creates a pixbuf,
49 * which represents the builtin theme in the preferences window.
51 void gd_create_pixbuf_for_builtin_theme()
53 /* use gdash palette */
54 gd_select_pixbuf_colors(GD_GDASH_BLACK
, GD_GDASH_MIDDLEBLUE
, GD_GDASH_LIGHTRED
, GD_GDASH_WHITE
, GD_GDASH_WHITE
, GD_GDASH_WHITE
);
55 gd_pixbuf_for_builtin_theme
=gdk_pixbuf_copy(cells_pb
[ABS(gd_elements
[O_PLAYER
].image_game
)]);
59 /* used by the editor for the element pick dialog */
61 gd_current_background_color()
63 if (color0
!=GD_COLOR_INVALID
)
65 return GD_GDASH_BLACK
;
69 /* wrapper around scale2x defined in gfxutil.c */
71 scale2x(GdkPixbuf
*src
)
75 g_assert(gdk_pixbuf_get_colorspace(src
)==GDK_COLORSPACE_RGB
);
76 g_assert(gdk_pixbuf_get_has_alpha(src
));
77 g_assert(gdk_pixbuf_get_n_channels(src
)==4);
78 g_assert(gdk_pixbuf_get_bits_per_sample(src
)==8);
80 dst
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, 2*gdk_pixbuf_get_width(src
), 2*gdk_pixbuf_get_height(src
));
82 gd_scale2x_raw(gdk_pixbuf_get_pixels(src
), gdk_pixbuf_get_width(src
), gdk_pixbuf_get_height(src
), gdk_pixbuf_get_rowstride(src
), gdk_pixbuf_get_pixels(dst
), gdk_pixbuf_get_rowstride(dst
));
87 /* wrapper around scale3x defined in gfxutil.c */
89 scale3x(GdkPixbuf
*src
)
93 g_assert(gdk_pixbuf_get_colorspace(src
)==GDK_COLORSPACE_RGB
);
94 g_assert(gdk_pixbuf_get_has_alpha(src
));
95 g_assert(gdk_pixbuf_get_n_channels(src
)==4);
96 g_assert(gdk_pixbuf_get_bits_per_sample(src
)==8);
98 dst
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, 3*gdk_pixbuf_get_width(src
), 3*gdk_pixbuf_get_height(src
));
100 gd_scale3x_raw(gdk_pixbuf_get_pixels(src
), gdk_pixbuf_get_width(src
), gdk_pixbuf_get_height(src
), gdk_pixbuf_get_rowstride(src
), gdk_pixbuf_get_pixels(dst
), gdk_pixbuf_get_rowstride(dst
));
105 /* scale4x is essentially a scale2x applied twice */
107 scale4x(GdkPixbuf
*src
)
109 GdkPixbuf
*dst2x
, *dst
;
111 g_assert(gdk_pixbuf_get_colorspace(src
)==GDK_COLORSPACE_RGB
);
112 g_assert(gdk_pixbuf_get_has_alpha(src
));
113 g_assert(gdk_pixbuf_get_n_channels(src
)==4);
114 g_assert(gdk_pixbuf_get_bits_per_sample(src
)==8);
116 dst2x
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, 2*gdk_pixbuf_get_width(src
), 2*gdk_pixbuf_get_height(src
));
117 dst
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, 4*gdk_pixbuf_get_width(src
), 4*gdk_pixbuf_get_height(src
));
119 gd_scale2x_raw(gdk_pixbuf_get_pixels(src
), gdk_pixbuf_get_width(src
), gdk_pixbuf_get_height(src
), gdk_pixbuf_get_rowstride(src
), gdk_pixbuf_get_pixels(dst2x
), gdk_pixbuf_get_rowstride(dst2x
));
121 gd_scale2x_raw(gdk_pixbuf_get_pixels(dst2x
), gdk_pixbuf_get_width(dst2x
), gdk_pixbuf_get_height(dst2x
), gdk_pixbuf_get_rowstride(dst2x
), gdk_pixbuf_get_pixels(dst
), gdk_pixbuf_get_rowstride(dst
));
123 g_object_unref(dst2x
);
131 /* scales a pixbuf with the appropriate scaling type. */
133 gd_pixbuf_scale(GdkPixbuf
*orig
, GdScalingType type
)
135 GdkPixbuf
*pixbuf
=NULL
;
138 case GD_SCALING_ORIGINAL
:
139 pixbuf
=gdk_pixbuf_copy(orig
);
143 pixbuf
=gdk_pixbuf_scale_simple(orig
, 2*gdk_pixbuf_get_width(orig
), 2*gdk_pixbuf_get_height(orig
), GDK_INTERP_NEAREST
);
146 case GD_SCALING_2X_BILINEAR
:
147 pixbuf
=gdk_pixbuf_scale_simple(orig
, 2*gdk_pixbuf_get_width(orig
), 2*gdk_pixbuf_get_height(orig
), GDK_INTERP_BILINEAR
);
150 case GD_SCALING_2X_SCALE2X
:
151 pixbuf
=scale2x(orig
);
155 pixbuf
=gdk_pixbuf_scale_simple(orig
, 3*gdk_pixbuf_get_width(orig
), 3*gdk_pixbuf_get_height(orig
), GDK_INTERP_NEAREST
);
158 case GD_SCALING_3X_BILINEAR
:
159 pixbuf
=gdk_pixbuf_scale_simple(orig
, 3*gdk_pixbuf_get_width(orig
), 3*gdk_pixbuf_get_height(orig
), GDK_INTERP_BILINEAR
);
162 case GD_SCALING_3X_SCALE3X
:
163 pixbuf
=scale3x(orig
);
167 pixbuf
=gdk_pixbuf_scale_simple(orig
, 4*gdk_pixbuf_get_width(orig
), 4*gdk_pixbuf_get_height(orig
), GDK_INTERP_NEAREST
);
170 case GD_SCALING_4X_BILINEAR
:
171 pixbuf
=gdk_pixbuf_scale_simple(orig
, 4*gdk_pixbuf_get_width(orig
), 4*gdk_pixbuf_get_height(orig
), GDK_INTERP_BILINEAR
);
174 case GD_SCALING_4X_SCALE4X
:
175 pixbuf
=scale4x(orig
);
179 /* to avoid compiler warning */
180 g_assert_not_reached();
188 draw an element - usually an arrow or something like that
191 the destination element's editor drawing will be used.
192 the source element will be a game element.
195 add_arrow_to_cell(GdElement dest
, GdElement src
, GdElement arrow
, GdkPixbufRotation rotation
)
197 int pixbuf_cell_size
=gdk_pixbuf_get_height(cells_pb
[0]);
198 GdkPixbuf
*arrow_pb
=gdk_pixbuf_rotate_simple(cells_pb
[gd_elements
[arrow
].image
], rotation
); /* arrow */
200 if (gd_elements
[dest
].image
<NUM_OF_CELLS_X
*NUM_OF_CELLS_Y
) {
201 g_critical("destination index %d<NUM_OF_CELLS_X*NUM_OF_CELLS_Y, element %s", dest
, gd_elements
[dest
].name
);
202 g_assert_not_reached();
205 if (gd_elements
[dest
].image
>=NUM_OF_CELLS
) {
206 g_critical("destination index %d>=NUM_OF_CELLS, element %s", dest
, gd_elements
[dest
].name
);
207 g_assert_not_reached();
209 if (cells_pb
[gd_elements
[dest
].image
]!=NULL
) {
210 g_critical("destination index %d!=NULL, element %s", dest
, gd_elements
[dest
].name
);
211 g_assert_not_reached();
214 /* editor image <- game image */
215 cells_pb
[gd_elements
[dest
].image
]=gdk_pixbuf_copy(cells_pb
[ABS(gd_elements
[src
].image_game
)]);
216 /* composite arrow to copy */
217 gdk_pixbuf_composite (arrow_pb
, cells_pb
[gd_elements
[dest
].image
], 0, 0, pixbuf_cell_size
, pixbuf_cell_size
, 0, 0, 1, 1, GDK_INTERP_NEAREST
, 255);
218 g_object_unref (arrow_pb
);
222 copy_cell(int dest
, int src
)
224 g_assert(cells_pb
[dest
]==NULL
);
225 g_assert(src
<NUM_OF_CELLS
);
226 cells_pb
[dest
]=gdk_pixbuf_copy (cells_pb
[src
]);
230 composite two elements.
233 create_composite_cell_pixbuf(GdElement dest
, GdElement src1
, GdElement src2
)
235 int pixbuf_cell_size
=gdk_pixbuf_get_height (cells_pb
[0]);
237 g_assert(gd_elements
[dest
].image
<NUM_OF_CELLS
);
238 g_assert(cells_pb
[gd_elements
[dest
].image
]==NULL
);
240 /* destination image=source1 */
241 cells_pb
[gd_elements
[dest
].image
]=gdk_pixbuf_copy(cells_pb
[gd_elements
[src1
].image
]);
242 /* composite source2 to destination */
243 gdk_pixbuf_composite(cells_pb
[gd_elements
[src2
].image
], cells_pb
[gd_elements
[dest
].image
], 0, 0, pixbuf_cell_size
, pixbuf_cell_size
, 0, 0, 1, 1, GDK_INTERP_NEAREST
, 85);
246 /* check if pixbuf is suitable for a theme.
247 report_error=TRUE, then it will send warning messages if it isn't.
250 gd_is_pixbuf_ok_for_theme(GdkPixbuf
*pixbuf
)
252 static char *error
=NULL
;
255 g_assert(pixbuf
!=NULL
);
260 width
=gdk_pixbuf_get_width(pixbuf
);
261 height
=gdk_pixbuf_get_height(pixbuf
);
263 if ((width
% NUM_OF_CELLS_X
!= 0) || (height
% NUM_OF_CELLS_Y
!= 0) || (width
/ NUM_OF_CELLS_X
!= height
/ NUM_OF_CELLS_Y
)) {
264 error
=g_strdup_printf("Image should contain %d cells in a row and %d in a column!", NUM_OF_CELLS_X
, NUM_OF_CELLS_Y
);
267 if (!gdk_pixbuf_get_has_alpha(pixbuf
)) {
268 error
=g_strdup_printf("Image should have an alpha channel!");
276 /* check if file is suitable for a theme.
277 report_error=TRUE, then it will send warning messages if it isn't.
280 gd_is_image_ok_for_theme(const char *filename
)
285 static char *error_msg
=NULL
;
286 const char *error_from_pixbuf
;
288 g_assert(filename
!=NULL
);
294 pixbuf
=gdk_pixbuf_new_from_file (filename
, &error
);
296 error_msg
=g_strdup(error
->message
);
300 error_from_pixbuf
=gd_is_pixbuf_ok_for_theme(pixbuf
);
301 g_object_unref(pixbuf
);
303 if (error_from_pixbuf
) {
304 error_msg
=g_strdup(error_from_pixbuf
);
308 return NULL
; /* passed tests */
311 /* remove pixmaps from x server */
317 /* if cells already loaded, unref them */
318 for (i
=0; i
<G_N_ELEMENTS(cells_game
); i
++) {
320 g_object_unref(cells_game
[i
]);
323 /* if cells already loaded, unref them */
324 for (i
=0; i
<G_N_ELEMENTS(cells_editor
); i
++) {
326 g_object_unref(cells_editor
[i
]);
327 cells_editor
[i
]=NULL
;
331 /* returns true, if the given pixbuf seems to be a c64 imported image. */
333 check_if_pixbuf_c64_png (GdkPixbuf
*pixbuf
)
335 int width
, height
, rowstride
, n_channels
;
339 n_channels
=gdk_pixbuf_get_n_channels (pixbuf
);
341 g_assert (gdk_pixbuf_get_colorspace (pixbuf
) == GDK_COLORSPACE_RGB
);
342 g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf
) == 8);
343 g_assert (gdk_pixbuf_get_has_alpha (pixbuf
));
344 g_assert (n_channels
== 4);
346 width
=gdk_pixbuf_get_width (pixbuf
);
347 height
=gdk_pixbuf_get_height (pixbuf
);
349 rowstride
=gdk_pixbuf_get_rowstride (pixbuf
);
350 pixels
=gdk_pixbuf_get_pixels (pixbuf
);
352 for (y
=0; y
<height
; y
++) {
353 p
=pixels
+ y
* rowstride
;
354 for (x
=0; x
<width
*n_channels
; x
++)
355 if (p
[x
]!=0 && p
[x
]!=255)
361 /* load cells, eg. create cells_pb and combo_pb
365 loadcells_from_pixbuf(GdkPixbuf
*cells_pixbuf
)
368 int pixbuf_cell_size
;
370 /* now that we have the pixbuf, we can start freeing old graphics. */
371 for (i
=0; i
<G_N_ELEMENTS(cells_pb
); i
++) {
373 g_object_unref (cells_pb
[i
]);
376 /* scaled cells for editor combo boxes. created by editor, but we free them if we load a new theme */
378 g_object_unref (combo_pb
[i
]);
382 /* if we have scaled pixmaps, remove them */
385 /* 8 (NUM_OF_CELLS_X) cells in a row, so divide by it and we get the size of a cell in pixels */
386 pixbuf_cell_size
=gdk_pixbuf_get_width (cells_pixbuf
) / NUM_OF_CELLS_X
;
388 /* make individual cell pixbufs */
389 for (i
=0; i
< NUM_OF_CELLS_Y
*NUM_OF_CELLS_X
; i
++)
391 cells_pb
[i
]=gdk_pixbuf_new_subpixbuf (cells_pixbuf
, (i
%NUM_OF_CELLS_X
) * pixbuf_cell_size
, (i
/NUM_OF_CELLS_X
) * pixbuf_cell_size
, pixbuf_cell_size
, pixbuf_cell_size
);
394 gd_cell_size_game
=pixbuf_cell_size
*gd_scaling_scale
[gd_cell_scale_game
];
395 gd_cell_size_editor
=pixbuf_cell_size
*gd_scaling_scale
[gd_cell_scale_editor
];
397 /* draw some elements, combining them with arrows and the like */
398 add_arrow_to_cell(O_STEEL_EATABLE
, O_STEEL
, O_EATABLE
, GDK_PIXBUF_ROTATE_NONE
);
399 add_arrow_to_cell(O_BRICK_EATABLE
, O_BRICK
, O_EATABLE
, GDK_PIXBUF_ROTATE_NONE
);
400 create_composite_cell_pixbuf(O_BRICK_NON_SLOPED
, O_STEEL
, O_BRICK
);
402 create_composite_cell_pixbuf(O_WALLED_KEY_1
, O_KEY_1
, O_BRICK
);
403 create_composite_cell_pixbuf(O_WALLED_KEY_2
, O_KEY_2
, O_BRICK
);
404 create_composite_cell_pixbuf(O_WALLED_KEY_3
, O_KEY_3
, O_BRICK
);
405 create_composite_cell_pixbuf(O_WALLED_DIAMOND
, O_DIAMOND
, O_BRICK
);
407 add_arrow_to_cell(O_FIREFLY_1
, O_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
408 add_arrow_to_cell(O_FIREFLY_2
, O_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
409 add_arrow_to_cell(O_FIREFLY_3
, O_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
410 add_arrow_to_cell(O_FIREFLY_4
, O_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
412 add_arrow_to_cell(O_ALT_FIREFLY_1
, O_ALT_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
413 add_arrow_to_cell(O_ALT_FIREFLY_2
, O_ALT_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
414 add_arrow_to_cell(O_ALT_FIREFLY_3
, O_ALT_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
415 add_arrow_to_cell(O_ALT_FIREFLY_4
, O_ALT_FIREFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
417 add_arrow_to_cell(O_H_EXPANDING_WALL
, O_H_EXPANDING_WALL
, O_LEFTRIGHT_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
418 add_arrow_to_cell(O_V_EXPANDING_WALL
, O_V_EXPANDING_WALL
, O_LEFTRIGHT_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
419 add_arrow_to_cell(O_EXPANDING_WALL
, O_EXPANDING_WALL
, O_EVERYDIR_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
421 add_arrow_to_cell(O_H_EXPANDING_STEEL_WALL
, O_H_EXPANDING_STEEL_WALL
, O_LEFTRIGHT_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
422 add_arrow_to_cell(O_V_EXPANDING_STEEL_WALL
, O_V_EXPANDING_STEEL_WALL
, O_LEFTRIGHT_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
423 add_arrow_to_cell(O_EXPANDING_STEEL_WALL
, O_EXPANDING_STEEL_WALL
, O_EVERYDIR_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
425 add_arrow_to_cell(O_BUTTER_1
, O_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
426 add_arrow_to_cell(O_BUTTER_2
, O_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
427 add_arrow_to_cell(O_BUTTER_3
, O_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
428 add_arrow_to_cell(O_BUTTER_4
, O_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
430 add_arrow_to_cell(O_DRAGONFLY_1
, O_DRAGONFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
431 add_arrow_to_cell(O_DRAGONFLY_2
, O_DRAGONFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
432 add_arrow_to_cell(O_DRAGONFLY_3
, O_DRAGONFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
433 add_arrow_to_cell(O_DRAGONFLY_4
, O_DRAGONFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
435 add_arrow_to_cell(O_COW_1
, O_COW_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
436 add_arrow_to_cell(O_COW_2
, O_COW_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
437 add_arrow_to_cell(O_COW_3
, O_COW_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
438 add_arrow_to_cell(O_COW_4
, O_COW_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
439 add_arrow_to_cell(O_COW_ENCLOSED_1
, O_COW_1
, O_GLUED
, GDK_PIXBUF_ROTATE_NONE
);
441 add_arrow_to_cell(O_ALT_BUTTER_1
, O_ALT_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
442 add_arrow_to_cell(O_ALT_BUTTER_2
, O_ALT_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
443 add_arrow_to_cell(O_ALT_BUTTER_3
, O_ALT_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
444 add_arrow_to_cell(O_ALT_BUTTER_4
, O_ALT_BUTTER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
446 add_arrow_to_cell(O_PLAYER_GLUED
, O_PLAYER
, O_GLUED
, 0);
447 add_arrow_to_cell(O_PLAYER
, O_PLAYER
, O_EXCLAMATION_MARK
, 0);
448 add_arrow_to_cell(O_STONE_GLUED
, O_STONE
, O_GLUED
, 0);
449 add_arrow_to_cell(O_DIAMOND_GLUED
, O_DIAMOND
, O_GLUED
, 0);
450 add_arrow_to_cell(O_DIRT_GLUED
, O_DIRT
, O_GLUED
, 0);
451 add_arrow_to_cell(O_STONE_F
, O_STONE
, O_DOWN_ARROW
, 0);
452 add_arrow_to_cell(O_FLYING_STONE_F
, O_FLYING_STONE
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
453 add_arrow_to_cell(O_MEGA_STONE_F
, O_MEGA_STONE
, O_DOWN_ARROW
, 0);
454 add_arrow_to_cell(O_DIAMOND_F
, O_DIAMOND
, O_DOWN_ARROW
, 0);
455 add_arrow_to_cell(O_FLYING_DIAMOND_F
, O_FLYING_DIAMOND
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
456 add_arrow_to_cell(O_NUT_F
, O_NUT
, O_DOWN_ARROW
, 0);
457 add_arrow_to_cell(O_FALLING_WALL
, O_BRICK
, O_EXCLAMATION_MARK
, 0);
458 add_arrow_to_cell(O_FALLING_WALL_F
, O_BRICK
, O_DOWN_ARROW
, 0);
459 add_arrow_to_cell(O_TIME_PENALTY
, O_GRAVESTONE
, O_EXCLAMATION_MARK
, 0);
460 add_arrow_to_cell(O_NITRO_PACK_F
, O_NITRO_PACK
, O_DOWN_ARROW
, 0);
461 add_arrow_to_cell(O_NITRO_PACK_EXPLODE
, O_NITRO_PACK
, O_EXCLAMATION_MARK
, 0);
462 add_arrow_to_cell(O_CONVEYOR_LEFT
, O_CONVEYOR_LEFT
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
463 add_arrow_to_cell(O_CONVEYOR_RIGHT
, O_CONVEYOR_RIGHT
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
465 add_arrow_to_cell(O_STONEFLY_1
, O_STONEFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
466 add_arrow_to_cell(O_STONEFLY_2
, O_STONEFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
467 add_arrow_to_cell(O_STONEFLY_3
, O_STONEFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
468 add_arrow_to_cell(O_STONEFLY_4
, O_STONEFLY_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
470 add_arrow_to_cell(O_BITER_1
, O_BITER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_UPSIDEDOWN
);
471 add_arrow_to_cell(O_BITER_2
, O_BITER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE
);
472 add_arrow_to_cell(O_BITER_3
, O_BITER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_NONE
);
473 add_arrow_to_cell(O_BITER_4
, O_BITER_1
, O_DOWN_ARROW
, GDK_PIXBUF_ROTATE_CLOCKWISE
);
475 add_arrow_to_cell(O_PRE_INVIS_OUTBOX
, O_OUTBOX_CLOSED
, O_GLUED
, GDK_PIXBUF_ROTATE_NONE
);
476 add_arrow_to_cell(O_PRE_OUTBOX
, O_OUTBOX_OPEN
, O_GLUED
, GDK_PIXBUF_ROTATE_NONE
);
477 add_arrow_to_cell(O_INVIS_OUTBOX
, O_OUTBOX_CLOSED
, O_OUT
, GDK_PIXBUF_ROTATE_NONE
);
478 add_arrow_to_cell(O_OUTBOX
, O_OUTBOX_OPEN
, O_OUT
, GDK_PIXBUF_ROTATE_NONE
);
480 add_arrow_to_cell(O_UNKNOWN
, O_STEEL
, O_QUESTION_MARK
, GDK_PIXBUF_ROTATE_NONE
);
481 add_arrow_to_cell(O_WAITING_STONE
, O_STONE
, O_EXCLAMATION_MARK
, GDK_PIXBUF_ROTATE_NONE
);
483 /* blinking outbox: helps editor, drawing the cave is more simple */
484 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+0, gd_elements
[O_OUTBOX_OPEN
].image_game
);
485 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+1, gd_elements
[O_OUTBOX_OPEN
].image_game
);
486 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+2, gd_elements
[O_OUTBOX_OPEN
].image_game
);
487 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+3, gd_elements
[O_OUTBOX_OPEN
].image_game
);
488 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+4, gd_elements
[O_OUTBOX_CLOSED
].image_game
);
489 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+5, gd_elements
[O_OUTBOX_CLOSED
].image_game
);
490 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+6, gd_elements
[O_OUTBOX_CLOSED
].image_game
);
491 copy_cell(ABS(gd_elements
[O_PRE_OUTBOX
].image_simple
)+7, gd_elements
[O_OUTBOX_CLOSED
].image_game
);
495 rgba_pixel_from_color(GdColor col
, guint8 a
)
497 guint8 r
=gd_color_get_r(col
);
498 guint8 g
=gd_color_get_g(col
);
499 guint8 b
=gd_color_get_b(col
);
500 #if G_BYTE_ORDER==G_LITTLE_ENDIAN
501 return r
+(g
<<8)+(b
<<16)+(a
<<24);
503 return (r
<<24)+(g
<<16)+(b
<<8)+a
;
508 loadcells_c64_with_colors (GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
510 const guchar
*gfx
; /* currently used graphics, will point to c64_gfx or c64_custom_gfx */
511 GdkPixbuf
*cells_pixbuf
;
512 guint32 cols
[9]; /* holds rgba for color indexes internally used */
513 int rowstride
, n_channels
;
517 gfx
=c64_custom_gfx
?c64_custom_gfx
:c64_gfx
;
519 cols
[0]=rgba_pixel_from_color(0, 0);
520 cols
[1]=rgba_pixel_from_color(c0
, 0xff); /* c64 background */
521 cols
[2]=rgba_pixel_from_color(c1
, 0xff); /* foreg1 */
522 cols
[3]=rgba_pixel_from_color(c2
, 0xff); /* foreg2 */
523 cols
[4]=rgba_pixel_from_color(c3
, 0xff); /* foreg3 */
524 cols
[5]=rgba_pixel_from_color(c4
, 0xff); /* amoeba */
525 cols
[6]=rgba_pixel_from_color(c5
, 0xff); /* slime */
526 cols
[7]=rgba_pixel_from_color(0, 0xff); /* black, opaque*/
527 cols
[8]=rgba_pixel_from_color(0xffffff, 0xff); /* white, opaque*/
529 cells_pixbuf
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, NUM_OF_CELLS_X
*gfx
[0], NUM_OF_CELLS_Y
*gfx
[0]);
530 n_channels
=gdk_pixbuf_get_n_channels (cells_pixbuf
);
531 rowstride
=gdk_pixbuf_get_rowstride (cells_pixbuf
); /* bytes / row */
532 pixels
=gdk_pixbuf_get_pixels (cells_pixbuf
); /* pointer to pixbuf memory */
534 pos
=1; /* index to gfx array */
535 /* create colored pixbuf from c64 graphics, using c0, c1, c2, c3 */
536 for (y
=0; y
<NUM_OF_CELLS_Y
*gfx
[0]; y
++) {
537 guint32
*p
=(guint32
*) (pixels
+ y
* rowstride
); /* write 32bits at once - faster than writing bytes */
539 for (x
=0; x
<NUM_OF_CELLS_X
*gfx
[0]; x
++)
540 p
[x
]=cols
[(int) gfx
[pos
++]];
543 /* from here, same as any other png */
544 loadcells_from_pixbuf(cells_pixbuf
);
545 g_object_unref(cells_pixbuf
);
551 c64_gfx_data_from_pixbuf(GdkPixbuf
*pixbuf
)
553 int width
, height
, rowstride
, n_channels
;
559 g_assert (gdk_pixbuf_get_colorspace (pixbuf
) == GDK_COLORSPACE_RGB
);
560 g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf
) == 8);
561 g_assert (gdk_pixbuf_get_has_alpha (pixbuf
));
563 n_channels
=gdk_pixbuf_get_n_channels (pixbuf
);
564 width
=gdk_pixbuf_get_width (pixbuf
);
565 height
=gdk_pixbuf_get_height (pixbuf
);
566 rowstride
=gdk_pixbuf_get_rowstride (pixbuf
);
567 pixels
=gdk_pixbuf_get_pixels (pixbuf
);
569 g_assert (n_channels
== 4);
571 data
=g_new(guchar
, width
*height
+1);
573 data
[out
++]=width
/NUM_OF_CELLS_X
;
575 for (y
=0; y
<height
; y
++)
576 for (x
=0; x
<width
; x
++) {
579 guchar
*p
=pixels
+ y
* rowstride
+ x
* n_channels
;
584 data
[out
++]=c64_png_colors(r
, g
, b
, a
);
592 gd_loadcells_file(const char *filename
)
594 GdkPixbuf
*cells_pixbuf
;
596 const char *error_msg
;
598 /* load cell graphics */
600 cells_pixbuf
=gdk_pixbuf_new_from_file (filename
, &error
);
602 g_warning("%s", error
->message
);
606 /* check if file has the properties which we need for a theme */
607 error_msg
=gd_is_pixbuf_ok_for_theme(cells_pixbuf
);
609 g_object_unref(cells_pixbuf
);
610 g_warning("%s", error_msg
);
614 if (check_if_pixbuf_c64_png(cells_pixbuf
)) {
615 /* c64 pixbuf with a small number of colors which can be changed */
616 g_free(c64_custom_gfx
);
617 c64_custom_gfx
=c64_gfx_data_from_pixbuf(cells_pixbuf
);
620 /* normal, "truecolor" pixbuf */
621 g_free(c64_custom_gfx
);
623 loadcells_from_pixbuf(cells_pixbuf
);
626 g_object_unref(cells_pixbuf
);
627 color0
=GD_COLOR_INVALID
; /* so that pixbufs will be recreated */
633 gd_loadcells_default()
635 g_free(c64_custom_gfx
);
638 color0
=GD_COLOR_INVALID
; /* so that pixbufs will be recreated */
640 /* size of array (in bytes), -1 which is the cell size */
641 g_assert(sizeof(c64_gfx
)-1 == NUM_OF_CELLS_X
*NUM_OF_CELLS_Y
*c64_gfx
[0]*c64_gfx
[0]);
645 /* exported for settings window */
647 gd_pal_emulate_pixbuf(GdkPixbuf
*pixbuf
)
649 #if G_BYTE_ORDER == G_BIG_ENDIAN
660 g_assert(gdk_pixbuf_get_has_alpha(pixbuf
));
662 gd_pal_emulate_raw(gdk_pixbuf_get_pixels(pixbuf
), gdk_pixbuf_get_width(pixbuf
), gdk_pixbuf_get_height(pixbuf
), gdk_pixbuf_get_rowstride(pixbuf
), rshift
, gshift
, bshift
, ashift
);
665 /* create pixmap for image number 'index', using cell size. */
666 /* a pixmap * array is to be given; that may be cells_game or cells_editor */
667 /* pal emulation does just that. */
668 /* if render_selected is true, it will render the blue cell, too - that is used only in the editor. */
670 create_pixmap(GdkPixmap
**cells
, int index
, int cell_size
, GdScalingType type
, gboolean render_selected
, gboolean pal_emul
)
672 GdkPixbuf
*selected
, *normal
, *element
;
675 g_assert(index
>=0 && index
<NUM_OF_CELLS
);
676 g_assert(cells_pb
[index
]!=NULL
);
678 window
=gdk_get_default_root_window();
681 * scale every cell on its own, or else some pixels might be merged on borders */
682 normal
=gd_pixbuf_scale(cells_pb
[index
], type
);
684 gd_pal_emulate_pixbuf(normal
);
685 /* create colored cells. */
686 /* here no scaling is done, so interp_nearest is ok. */
688 /* create pixmap containing pixbuf */
689 /* draw the pixbufs to the new pixmaps */
690 cells
[index
]=gdk_pixmap_new (window
, cell_size
, cell_size
, -1);
691 gdk_draw_pixbuf(cells
[index
], NULL
, normal
, 0, 0, 0, 0, cell_size
, cell_size
, GDK_RGB_DITHER_MAX
, 0, 0);
693 element
=gdk_pixbuf_composite_color_simple(normal
, cell_size
, cell_size
, GDK_INTERP_NEAREST
, 128, 1, gd_flash_color
, gd_flash_color
);
694 cells
[NUM_OF_CELLS
+ index
]=gdk_pixmap_new (window
, cell_size
, cell_size
, -1);
695 gdk_draw_pixbuf(cells
[NUM_OF_CELLS
+ index
], NULL
, element
, 0, 0, 0, 0, cell_size
, cell_size
, GDK_RGB_DITHER_MAX
, 0, 0);
696 g_object_unref(element
);
698 if (render_selected
) {
699 selected
=gdk_pixbuf_composite_color_simple(normal
, cell_size
, cell_size
, GDK_INTERP_NEAREST
, 128, 1, gd_select_color
, gd_select_color
);
700 cells
[2 * NUM_OF_CELLS
+ index
]=gdk_pixmap_new (window
, cell_size
, cell_size
, -1);
701 gdk_draw_pixbuf(cells
[2 * NUM_OF_CELLS
+ index
], NULL
, selected
, 0, 0, 0, 0, cell_size
, cell_size
, GDK_RGB_DITHER_MAX
, 0, 0);
702 g_object_unref(selected
);
705 /* forget scaled pixbufs, as only the pixmaps are needed */
706 g_object_unref(normal
);
709 /* return a pixmap scaled for the game */
711 gd_game_pixmap(int index
)
715 g_assert(index
<2*NUM_OF_CELLS
); /* make sure that no blue/"selected" pixbuf is requested for a game */
716 i
=index
%NUM_OF_CELLS
; /* might request a colored, so we do a % NUM_OF_CELLS */
717 if (cells_game
[i
]==NULL
) /* check if pixmap already exists */
718 create_pixmap(cells_game
, i
, gd_cell_size_game
, gd_cell_scale_game
, FALSE
, gd_pal_emulation_game
);
719 return cells_game
[index
];
722 /* return a pixmap scaled for the editor */
724 gd_editor_pixmap(int index
)
728 i
=index
%NUM_OF_CELLS
; /* might request a colored, so we do a % NUM_OF_CELLS */
729 if (cells_editor
[i
]==NULL
) /* check if pixmap already exists */
730 create_pixmap(cells_editor
, i
, gd_cell_size_editor
, gd_cell_scale_editor
, TRUE
, gd_pal_emulation_editor
);
731 return cells_editor
[index
];
734 /* set pixbuf colors. */
735 /* (if png graphics is used, it does nothing. */
737 gd_select_pixbuf_colors(GdColor c0
, GdColor c1
, GdColor c2
, GdColor c3
, GdColor c4
, GdColor c5
)
739 /* if non-c64 gfx, nothing to do */
743 /* convert to rgb value */
744 c0
=gd_color_get_rgb(c0
);
745 c1
=gd_color_get_rgb(c1
);
746 c2
=gd_color_get_rgb(c2
);
747 c3
=gd_color_get_rgb(c3
);
748 c4
=gd_color_get_rgb(c4
);
749 c5
=gd_color_get_rgb(c5
);
751 /* and compare rgb values! */
752 if (c0
!=color0
|| c1
!=color1
|| c2
!=color2
|| c3
!=color3
|| c4
!=color4
|| c5
!=color5
) {
753 /* if not the same colors as requested before */
761 loadcells_c64_with_colors(c0
, c1
, c2
, c3
, c4
, c5
);
767 get_element_pixbuf_with_border(int index
)
769 if (!combo_pb
[index
]) {
770 /* create small size pixbuf if needed. */
772 GdkPixbuf
*pixbuf
, *pixbuf_border
;
774 /* scale pixbuf to that specified by gtk */
775 gtk_icon_size_lookup(GTK_ICON_SIZE_MENU
, &x
, &y
);
776 pixbuf
=gdk_pixbuf_scale_simple(cells_pb
[index
], x
, y
, GDK_INTERP_BILINEAR
);
777 /* draw a little black border around image, makes the icons look much better */
778 pixbuf_border
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, gdk_pixbuf_get_has_alpha (pixbuf
), 8, x
+2, y
+2);
779 gdk_pixbuf_fill(pixbuf_border
, 0x000000ff); /* RGBA: opaque black */
780 gdk_pixbuf_copy_area(pixbuf
, 0, 0, x
, y
, pixbuf_border
, 1, 1);
781 g_object_unref(pixbuf
);
782 combo_pb
[index
]=pixbuf_border
;
784 return combo_pb
[index
];
788 returns a cell pixbuf, scaled to gtk icon size.
789 it also adds a little black border, which makes them look much better
792 gd_get_element_pixbuf_with_border(GdElement element
)
795 /* which pixbuf to show? */
796 index
=ABS(gd_elements
[element
].image
);
797 return get_element_pixbuf_with_border(index
);
801 returns a cell pixbuf, scaled to gtk icon size.
802 it also adds a little black border, which makes them look much better
805 gd_get_element_pixbuf_simple_with_border (GdElement element
)
808 /* which pixbuf to show? */
809 index
=ABS(gd_elements
[element
].image_simple
);
810 return get_element_pixbuf_with_border(index
);
814 creates a pixbuf, which shows the cave.
815 if width and height are given (nonzero),
816 scale pixbuf proportionally, so it fits in width*height
817 pixels. otherwise return in original size.
818 up to the caller to unref the returned pixbuf.
819 also up to the caller to call this function only for rendered caves.
822 gd_drawcave_to_pixbuf(const GdCave
*cave
, const int width
, const int height
, const gboolean game_view
, const gboolean border
)
826 GdkPixbuf
*pixbuf
, *scaled
;
829 int borderadd
=border
?4:0, borderpos
=border
?2:0;
831 g_assert(cave
->map
!=NULL
);
833 /* if showing the visible part only */
839 /* showing entire cave - for example, overview in editor */
846 gd_select_pixbuf_colors(cave
->color0
, cave
->color1
, cave
->color2
, cave
->color3
, cave
->color4
, cave
->color5
);
848 /* get size of one cell in the original pixbuf */
849 cell_size
=gdk_pixbuf_get_width (cells_pb
[0]);
851 /* add two pixels black border: +4 +4 for width and height */
852 pixbuf
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, gdk_pixbuf_get_has_alpha (cells_pb
[0]), 8, (x2
-x1
+1)*cell_size
+borderadd
, (y2
-y1
+1)*cell_size
+borderadd
);
854 gdk_pixbuf_fill(pixbuf
, 0x000000ff); /* fill with opaque black, so border is black */
856 /* take visible part into consideration */
857 for (y
=y1
; y
<=y2
; y
++)
858 for (x
=x1
; x
<=x2
; x
++) {
859 GdElement element
=cave
->map
[y
][x
]&O_MASK
;
866 element
=cave
->dirt_looks_like
;
868 case O_EXPANDING_WALL
:
869 case O_H_EXPANDING_WALL
:
870 case O_V_EXPANDING_WALL
:
871 /* only change the view, if it is not brick wall (the default value). */
872 /* so arrows remain - as well as they always remaing for the steel expanding wall,
873 which has no visual effect. */
874 if (cave
->expanding_wall_looks_like
!=O_BRICK
)
875 element
=cave
->expanding_wall_looks_like
;
878 element
=cave
->amoeba_2_looks_like
;
881 /* we check that this element has no visual effect. */
882 /* otherwise, we should have handled the element explicitely above! */
883 g_assert((gd_elements
[element
].properties
& P_VISUAL_EFFECT
) == 0);
886 draw
=ABS(gd_elements
[element
].image_simple
); /* pixbuf like in the editor */
889 draw
=gd_elements
[element
].image
; /* pixbuf like in the editor */
890 gdk_pixbuf_copy_area (cells_pb
[draw
], 0, 0, cell_size
, cell_size
, pixbuf
, (x
-x1
)*cell_size
+borderpos
, (y
-y1
)*cell_size
+borderpos
);
893 /* if requested size is 0, return unscaled */
894 if (width
== 0 || height
== 0)
897 /* decide which direction fits in rectangle */
898 /* cells are squares... no need to know cell_size here */
899 if ((float) gdk_pixbuf_get_width (pixbuf
) / (float) gdk_pixbuf_get_height (pixbuf
) >= (float) width
/ (float) height
)
900 scale
=width
/ ((float) gdk_pixbuf_get_width (pixbuf
));
902 scale
=height
/ ((float) gdk_pixbuf_get_height (pixbuf
));
904 /* scale to specified size */
905 scaled
=gdk_pixbuf_scale_simple (pixbuf
, gdk_pixbuf_get_width (pixbuf
)*scale
, gdk_pixbuf_get_height (pixbuf
)*scale
, GDK_INTERP_BILINEAR
);
906 g_object_unref (pixbuf
);
913 gd_pixbuf_load_from_data(guchar
*data
, int length
)
915 GdkPixbufLoader
*loader
;
919 /* push the data into a pixbuf loader */
920 loader
=gdk_pixbuf_loader_new();
921 if (!gdk_pixbuf_loader_write(loader
, data
, length
, &error
) || !gdk_pixbuf_loader_close(loader
, &error
)) {
922 g_warning("%s", error
->message
);
924 g_object_unref(loader
);
927 pixbuf
=gdk_pixbuf_loader_get_pixbuf(loader
);
928 g_object_ref(pixbuf
);
929 g_object_unref(loader
);
934 gd_pixbuf_load_from_base64(gchar
*base64
)
940 data
=g_base64_decode(base64
, &length
);
941 pixbuf
=gd_pixbuf_load_from_data(data
, length
);
950 /* create a pixbuf of the caveset-specific title image. */
951 /* if there is no such image, return null. */
953 gd_create_title_image()
957 GdkPixbuf
*screen
, *tile
, *tile_black
, *bigone
;
958 int w
, h
; /* screen (large image) width and height */
959 int tw
, th
; /* tile (small image) width and height */
962 if (gd_caveset_data
->title_screen
->len
==0)
965 data
=g_base64_decode(gd_caveset_data
->title_screen
->str
, &length
);
966 screen
=gd_pixbuf_load_from_data(data
, length
);
969 g_warning("Invalid title image stored in caveset.");
970 g_string_assign(gd_caveset_data
->title_screen
, ""); /* forget if it had some error... */
975 if (gd_caveset_data
->title_screen_scroll
->len
!=0) {
976 /* there is a tile, so load that also. */
977 data
=g_base64_decode(gd_caveset_data
->title_screen_scroll
->str
, &length
);
978 tile
=gd_pixbuf_load_from_data(data
, length
);
981 g_warning("Invalid title image scrolling background stored in caveset.");
982 g_string_assign(gd_caveset_data
->title_screen_scroll
, ""); /* forget if it had some error... */
987 w
=gdk_pixbuf_get_width(screen
);
988 h
=gdk_pixbuf_get_height(screen
);
991 /* one-row pixbuf, so no animation. */
992 tile
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, w
, 1);
993 gdk_pixbuf_fill(tile
, 0x000000FFU
); /* opaque black */
996 tw
=gdk_pixbuf_get_width(tile
);
997 th
=gdk_pixbuf_get_height(tile
);
999 /* either because the tile has no alpha channel, or because it cannot be transparent anymore... */
1000 /* also needed because the "bigone" pixbuf will have an alpha channel, and pixbuf_copy would not work otherwise. */
1001 tile_black
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, tw
, th
);
1002 gdk_pixbuf_fill(tile_black
, 0x000000FFU
); /* fill with opaque black, as even the tile may have an alpha channel */
1003 gdk_pixbuf_composite(tile
, tile_black
, 0, 0, tw
, th
, 0, 0, 1, 1, GDK_INTERP_NEAREST
, 255);
1004 g_object_unref(tile
);
1007 /* create a big image, which is one tile larger than the title image size */
1008 bigone
=gdk_pixbuf_new(GDK_COLORSPACE_RGB
, TRUE
, 8, w
, h
);
1009 /* and fill it with the tile. */
1010 for (y
=0; y
<h
; y
+=th
)
1011 for (x
=0; x
<w
; x
+=tw
) {
1012 int cw
, ch
; /* copied width and height */
1014 /* check if out of bounds, as gdk does not clip rather sends errors */
1023 gdk_pixbuf_copy_area(tile
, 0, 0, cw
, ch
, bigone
, x
, y
);
1025 g_object_unref(tile
);
1026 gdk_pixbuf_composite(screen
, bigone
, 0, 0, w
, h
, 0, 0, 1, 1, GDK_INTERP_NEAREST
, 255);
1027 g_object_unref(screen
);
1029 /* the image is now loaded and ready. */