1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Grabber plugin for editing alpha channels.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include <stdio.h>
20 #include <string.h>
21 
22 #include "allegro.h"
23 #include "allegro/internal/aintern.h"
24 #include "../datedit.h"
25 
26 
27 
28 /* creates a monochrome image containing the alpha channel of this bitmap */
get_alpha_bitmap(BITMAP * bmp)29 static BITMAP *get_alpha_bitmap(BITMAP *bmp)
30 {
31    BITMAP *alpha;
32    int x, y, c, a;
33    int got = FALSE;
34 
35    if (bitmap_color_depth(bmp) != 32)
36       return NULL;
37 
38    alpha = create_bitmap_ex(24, bmp->w, bmp->h);
39 
40    for (y=0; y<bmp->h; y++) {
41       for (x=0; x<bmp->w; x++) {
42 	 c = getpixel(bmp, x, y);
43 	 a = geta32(c);
44 	 putpixel(alpha, x, y, makecol24(a, a, a));
45 	 if (a)
46 	    got = TRUE;
47       }
48    }
49 
50    if (!got) {
51       destroy_bitmap(alpha);
52       return NULL;
53    }
54 
55    return alpha;
56 }
57 
58 
59 
60 /* checks whether the selection is capable of having an alpha channel */
alpha_query(int popup)61 static int alpha_query(int popup)
62 {
63    if (popup) {
64       DATAFILE *dat = grabber_single_selection();
65       return ((dat) && ((dat->type == DAT_BITMAP) || (dat->type == DAT_RLE_SPRITE)));
66    }
67 
68    return TRUE;
69 }
70 
71 
72 
73 /* views the current alpha channel */
view_alpha(void)74 static int view_alpha(void)
75 {
76    DATAFILE *dat = grabber_single_selection();
77    DATAFILE tmpdat;
78    RLE_SPRITE *rle;
79    BITMAP *bmp;
80    int ret = 0;
81    int i;
82 
83    if ((!dat) || ((dat->type != DAT_BITMAP) && (dat->type != DAT_RLE_SPRITE))) {
84       alert("You must select a single bitmap or RLE sprite",
85 	    "object before you can view the alpha channel",
86 	    NULL, "Sorry", NULL, 13, 0);
87       return 0;
88    }
89 
90    if (dat->type == DAT_RLE_SPRITE) {
91       rle = dat->dat;
92       bmp = create_bitmap_ex(rle->color_depth, rle->w, rle->h);
93       clear_to_color(bmp, bmp->vtable->mask_color);
94       draw_rle_sprite(bmp, rle, 0, 0);
95    }
96    else
97       bmp = dat->dat;
98 
99    tmpdat.dat = get_alpha_bitmap(bmp);
100 
101    if (tmpdat.dat) {
102       tmpdat.type = DAT_BITMAP;
103       tmpdat.size = 0;
104       tmpdat.prop = NULL;
105 
106       for (i=0; datedit_object_info[i]->type != DAT_END; i++) {
107 	 if ((datedit_object_info[i]->type == DAT_BITMAP) && (datedit_object_info[i]->dclick)) {
108 	    ret = datedit_object_info[i]->dclick(&tmpdat);
109 	    break;
110 	 }
111       }
112 
113       destroy_bitmap(tmpdat.dat);
114    }
115    else
116       alert("There is no alpha channel in this image", NULL, NULL, "Sorry", NULL, 13, 0);
117 
118    if (dat->type == DAT_RLE_SPRITE)
119       destroy_bitmap(bmp);
120 
121    return ret;
122 }
123 
124 
125 
126 /* exports the current alpha channel */
export_alpha(void)127 static int export_alpha(void)
128 {
129    DATAFILE *dat = grabber_single_selection();
130    DATAFILE tmpdat;
131    RLE_SPRITE *rle;
132    BITMAP *bmp;
133    char buf[256], name[FILENAME_LENGTH] = EMPTY_STRING;
134    AL_CONST char *ext;
135    int ret = 0;
136 
137    if ((!dat) || ((dat->type != DAT_BITMAP) && (dat->type != DAT_RLE_SPRITE))) {
138       alert("You must select a single bitmap or RLE sprite",
139 	    "object before you can export the alpha channel",
140 	    NULL, "Sorry", NULL, 13, 0);
141       return 0;
142    }
143 
144    if (dat->type == DAT_RLE_SPRITE) {
145       rle = dat->dat;
146       bmp = create_bitmap_ex(rle->color_depth, rle->w, rle->h);
147       clear_to_color(bmp, bmp->vtable->mask_color);
148       draw_rle_sprite(bmp, rle, 0, 0);
149    }
150    else
151       bmp = dat->dat;
152 
153    tmpdat.dat = get_alpha_bitmap(bmp);
154 
155    if (tmpdat.dat) {
156       tmpdat.type = DAT_BITMAP;
157       tmpdat.size = 0;
158       tmpdat.prop = NULL;
159 
160       ext = datedit_export_ext(DAT_BITMAP);
161       sprintf(buf, "Export alpha (%s)", ext);
162 
163       strcpy(name, grabber_import_file);
164       *get_filename(name) = 0;
165 
166       if (file_select_ex(buf, name, ext, sizeof(name), 0, 0)) {
167 	 fix_filename_case(name);
168 	 strcpy(grabber_import_file, name);
169 	 grabber_busy_mouse(TRUE);
170 	 datedit_export(&tmpdat, name);
171 	 grabber_busy_mouse(FALSE);
172       }
173 
174       destroy_bitmap(tmpdat.dat);
175       ret = D_REDRAW;
176    }
177    else
178       alert("There is no alpha channel in this image", NULL, NULL, "Sorry", NULL, 13, 0);
179 
180    if (dat->type == DAT_RLE_SPRITE)
181       destroy_bitmap(bmp);
182 
183    return ret;
184 }
185 
186 
187 
188 /* deletes the current alpha channel */
delete_alpha(void)189 static int delete_alpha(void)
190 {
191    DATAFILE *dat = grabber_single_selection();
192    RLE_SPRITE *rle;
193    BITMAP *bmp;
194    int got = FALSE;
195    int ret = 0;
196    int x, y, c, r, g, b, a;
197 
198    if ((!dat) || ((dat->type != DAT_BITMAP) && (dat->type != DAT_RLE_SPRITE))) {
199       alert("You must select a single bitmap or RLE sprite",
200 	    "object before you can delete the alpha channel",
201 	    NULL, "Sorry", NULL, 13, 0);
202       return 0;
203    }
204 
205    if (dat->type == DAT_RLE_SPRITE) {
206       rle = dat->dat;
207       bmp = create_bitmap_ex(rle->color_depth, rle->w, rle->h);
208       clear_to_color(bmp, bmp->vtable->mask_color);
209       draw_rle_sprite(bmp, rle, 0, 0);
210    }
211    else
212       bmp = dat->dat;
213 
214    if (bitmap_color_depth(bmp) == 32) {
215       for (y=0; y<bmp->h; y++) {
216 	 for (x=0; x<bmp->w; x++) {
217 	    c = getpixel(bmp, x, y);
218 	    r = getr32(c);
219 	    g = getg32(c);
220 	    b = getb32(c);
221 	    a = geta32(c);
222 	    putpixel(bmp, x, y, makecol32(r, g, b));
223 	    if (a)
224 	       got = TRUE;
225 	 }
226       }
227    }
228 
229    if (got) {
230       if (dat->type == DAT_RLE_SPRITE) {
231 	 destroy_rle_sprite(dat->dat);
232 	 dat->dat = get_rle_sprite(bmp);
233       }
234 
235       alert("Success: alpha channel moved to /dev/null", NULL, NULL, "Cool", NULL, 13, 0);
236       ret = D_REDRAW;
237    }
238    else
239       alert("There is no alpha channel in this image", NULL, NULL, "Sorry", NULL, 13, 0);
240 
241    if (dat->type == DAT_RLE_SPRITE)
242       destroy_bitmap(bmp);
243 
244    return ret;
245 }
246 
247 
248 
249 /* worker function for importing alpha channels */
do_alpha_import(BITMAP * bmp,int * changed,RGB * pal)250 static BITMAP *do_alpha_import(BITMAP *bmp, int *changed, RGB *pal)
251 {
252    BITMAP *newbmp;
253    DATAFILE *alpha;
254    char buf[256], name[FILENAME_LENGTH];
255    DATEDIT_GRAB_PARAMETERS params;
256    AL_CONST char *ext;
257    int x, y, c, r, g, b, a;
258 
259    *changed = FALSE;
260 
261    ext = datedit_grab_ext(DAT_BITMAP);
262    sprintf(buf, "Import alpha (%s)", ext);
263 
264    strcpy(name, grabber_import_file);
265    *get_filename(name) = 0;
266 
267    if (file_select_ex(buf, name, ext, sizeof(name), 0, 0)) {
268       fix_filename_case(name);
269       strcpy(grabber_import_file, name);
270       grabber_busy_mouse(TRUE);
271 
272       params.datafile = NULL;  /* only with absolute filenames */
273       params.filename = name;
274       params.name = name;
275       params.type = DAT_BITMAP;
276       params.x = -1;
277       params.y = -1;
278       params.w = -1;
279       params.h = -1;
280       params.colordepth = -1;
281       params.relative = FALSE;  /* required (see above) */
282 
283       alpha = datedit_grab(NULL, &params);
284 
285       if ((alpha) && (alpha->dat)) {
286 	 if (pal)
287 	    select_palette(pal);
288 
289 	 newbmp = create_bitmap_ex(32, bmp->w, bmp->h);
290 	 blit(bmp, newbmp, 0, 0, 0, 0, bmp->w, bmp->h);
291 	 destroy_bitmap(bmp);
292 	 bmp = newbmp;
293 
294 	 if (pal)
295 	    unselect_palette();
296 
297 	 select_palette(datedit_last_read_pal);
298 
299 	 for (y=0; y<bmp->h; y++) {
300 	    for (x=0; x<bmp->w; x++) {
301 	       if (getpixel(bmp, x, y) != bitmap_mask_color(bmp)) {
302 		  c = getpixel(alpha->dat, x, y);
303 		  r = getr_depth(bitmap_color_depth(alpha->dat), c);
304 		  g = getg_depth(bitmap_color_depth(alpha->dat), c);
305 		  b = getb_depth(bitmap_color_depth(alpha->dat), c);
306 		  a = (r+g+b)/3;
307 
308 		  bmp->line[y][x*4+_rgb_a_shift_32/8] = a;
309 	       }
310 	    }
311 	 }
312 
313 	 unselect_palette();
314 	 _unload_datafile_object(alpha);
315 
316 	 *changed = TRUE;
317       }
318 
319       grabber_busy_mouse(FALSE);
320    }
321 
322    return bmp;
323 }
324 
325 
326 
327 /* imports an alpha channel over the top of the current selection */
import_alpha(void)328 static int import_alpha(void)
329 {
330    DATAFILE *dat = grabber_single_selection();
331    RLE_SPRITE *rle;
332    BITMAP *bmp;
333    int changed;
334 
335    if ((!dat) || ((dat->type != DAT_BITMAP) && (dat->type != DAT_RLE_SPRITE))) {
336       alert("You must select a single bitmap or RLE sprite",
337 	    "object before you can import an alpha channel",
338 	    NULL, "Sorry", NULL, 13, 0);
339       return 0;
340    }
341 
342    if (dat->type == DAT_RLE_SPRITE) {
343       rle = dat->dat;
344       bmp = create_bitmap_ex(rle->color_depth, rle->w, rle->h);
345       clear_to_color(bmp, bmp->vtable->mask_color);
346       draw_rle_sprite(bmp, rle, 0, 0);
347       bmp = do_alpha_import(bmp, &changed, NULL);
348       destroy_rle_sprite(rle);
349       dat->dat = get_rle_sprite(bmp);
350       destroy_bitmap(bmp);
351    }
352    else
353       dat->dat = do_alpha_import(dat->dat, &changed, NULL);
354 
355    if (changed)
356       view_alpha();
357 
358    return D_REDRAW;
359 }
360 
361 
362 
363 /* reads an alpha channel over the top of the grab source bitmap */
read_alpha(void)364 static int read_alpha(void)
365 {
366    int changed;
367 
368    if (!grabber_graphic) {
369       alert("You must read in a bitmap file before", "you can add an alpha channel to it", NULL, "OK", NULL, 13, 0);
370       return 0;
371    }
372 
373    grabber_graphic = do_alpha_import(grabber_graphic, &changed, grabber_palette);
374 
375    if (changed)
376       alert("Alpha channel imported successfully: this will be", "used when you next grab a bitmap or RLE sprite", NULL, "OK", NULL, 13, 0);
377 
378    return D_REDRAW;
379 }
380 
381 
382 
383 /* menu commands for doing stuff to the alpha channel */
384 static MENU alpha_sub_menu[] =
385 {
386    { "&View Alpha",     view_alpha,    NULL,    0,    NULL  },
387    { "&Import Alpha",   import_alpha,  NULL,    0,    NULL  },
388    { "&Export Alpha",   export_alpha,  NULL,    0,    NULL  },
389    { "&Delete Alpha",   delete_alpha,  NULL,    0,    NULL  },
390    { NULL,              NULL,          NULL,    0,    NULL  }
391 };
392 
393 
394 
395 /* per-object alpha channel menu */
396 static MENU alpha_menu =
397 {
398    "Alpha Channel",
399    NULL,
400    alpha_sub_menu,
401    0,
402    NULL
403 };
404 
405 
406 
407 /* alpha channel command for the file menu */
408 static MENU read_alpha_menu =
409 {
410    "Read Alpha Channel",
411    read_alpha,
412    NULL,
413    0,
414    NULL
415 };
416 
417 
418 
419 /* plugin interface header */
420 DATEDIT_MENU_INFO datalpha_menu1 =
421 {
422    &alpha_menu,
423    alpha_query,
424    DATEDIT_MENU_POPUP | DATEDIT_MENU_OBJECT,
425    0,
426    NULL
427 };
428 
429 
430 
431 DATEDIT_MENU_INFO datalpha_menu2 =
432 {
433    &read_alpha_menu,
434    NULL,
435    DATEDIT_MENU_FILE,
436    0,
437    NULL
438 };
439 
440