1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Top level bitmap reading routines.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include <string.h>
20 
21 #include "allegro.h"
22 #include "allegro/internal/aintern.h"
23 
24 
25 
26 typedef struct BITMAP_TYPE_INFO
27 {
28    char *ext;
29    BITMAP *(*load)(AL_CONST char *filename, RGB *pal);
30    int (*save)(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal);
31    struct BITMAP_TYPE_INFO *next;
32 } BITMAP_TYPE_INFO;
33 
34 static BITMAP_TYPE_INFO *bitmap_type_list = NULL;
35 
36 
37 
38 /* register_bitmap_file_type:
39  *  Informs Allegro of a new image file type, telling it how to load and
40  *  save files of this format (either function may be NULL).
41  */
register_bitmap_file_type(AL_CONST char * ext,BITMAP * (* load)(AL_CONST char * filename,RGB * pal),int (* save)(AL_CONST char * filename,BITMAP * bmp,AL_CONST RGB * pal))42 void register_bitmap_file_type(AL_CONST char *ext, BITMAP *(*load)(AL_CONST char *filename, RGB *pal), int (*save)(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal))
43 {
44    char tmp[32], *aext;
45    BITMAP_TYPE_INFO *iter = bitmap_type_list;
46 
47    aext = uconvert_toascii(ext, tmp);
48    if (strlen(aext) == 0) return;
49 
50    if (!iter)
51       iter = bitmap_type_list = _AL_MALLOC(sizeof(struct BITMAP_TYPE_INFO));
52    else {
53       for (iter = bitmap_type_list; iter->next; iter = iter->next);
54       iter = iter->next = _AL_MALLOC(sizeof(struct BITMAP_TYPE_INFO));
55    }
56 
57    if (iter) {
58       iter->load = load;
59       iter->save = save;
60       iter->ext = _al_strdup(aext);
61       iter->next = NULL;
62    }
63 }
64 
65 
66 
67 /* load_bitmap:
68  *  Loads a bitmap from disk.
69  */
load_bitmap(AL_CONST char * filename,RGB * pal)70 BITMAP *load_bitmap(AL_CONST char *filename, RGB *pal)
71 {
72    char tmp[32], *aext;
73    BITMAP_TYPE_INFO *iter;
74    ASSERT(filename);
75 
76    aext = uconvert_toascii(get_extension(filename), tmp);
77 
78    for (iter = bitmap_type_list; iter; iter = iter->next) {
79       if (stricmp(iter->ext, aext) == 0) {
80 	 if (iter->load)
81 	    return iter->load(filename, pal);
82 	 return NULL;
83       }
84    }
85 
86    return NULL;
87 }
88 
89 
90 
91 /* save_bitmap:
92  *  Writes a bitmap to disk.
93  */
save_bitmap(AL_CONST char * filename,BITMAP * bmp,AL_CONST RGB * pal)94 int save_bitmap(AL_CONST char *filename, BITMAP *bmp, AL_CONST RGB *pal)
95 {
96    char tmp[32], *aext;
97    BITMAP_TYPE_INFO *iter;
98    ASSERT(filename);
99    ASSERT(bmp);
100 
101    aext = uconvert_toascii(get_extension(filename), tmp);
102 
103    for (iter = bitmap_type_list; iter; iter = iter->next) {
104       if (stricmp(iter->ext, aext) == 0) {
105 	 if (iter->save)
106 	    return iter->save(filename, bmp, pal);
107 	 return 1;
108       }
109    }
110 
111    return 1;
112 }
113 
114 
115 
116 /* _fixup_loaded_bitmap:
117  *  Helper function for adjusting the color depth of a loaded image.
118  *  Converts the bitmap BMP to the color depth BPP. If BMP is a 8-bit
119  *  bitmap, PAL must be the palette attached to the bitmap. If BPP is
120  *  equal to 8, the conversion is performed either by building a palette
121  *  optimized for the bitmap if PAL is not NULL (in which case PAL gets
122  *  filled in with this palette) or by using the current palette if PAL
123  *  is NULL. In any other cases, PAL is unused.
124  */
_fixup_loaded_bitmap(BITMAP * bmp,PALETTE pal,int bpp)125 BITMAP *_fixup_loaded_bitmap(BITMAP *bmp, PALETTE pal, int bpp)
126 {
127    BITMAP *b2;
128    ASSERT(bmp);
129 
130    b2 = create_bitmap_ex(bpp, bmp->w, bmp->h);
131    if (!b2) {
132       destroy_bitmap(bmp);
133       return NULL;
134    }
135 
136    if (bpp == 8) {
137       RGB_MAP *old_map = rgb_map;
138 
139       if (pal)
140 	 generate_optimized_palette(bmp, pal, NULL);
141       else
142 	 pal = _current_palette;
143 
144       rgb_map = _AL_MALLOC(sizeof(RGB_MAP));
145       if (rgb_map != NULL)
146 	 create_rgb_table(rgb_map, pal, NULL);
147 
148       blit(bmp, b2, 0, 0, 0, 0, bmp->w, bmp->h);
149 
150       if (rgb_map != NULL)
151 	 _AL_FREE(rgb_map);
152       rgb_map = old_map;
153    }
154    else if (bitmap_color_depth(bmp) == 8) {
155       select_palette(pal);
156       blit(bmp, b2, 0, 0, 0, 0, bmp->w, bmp->h);
157       unselect_palette();
158    }
159    else {
160       blit(bmp, b2, 0, 0, 0, 0, bmp->w, bmp->h);
161    }
162 
163    destroy_bitmap(bmp);
164 
165    return b2;
166 }
167 
168 
169 
170 /* register_bitmap_file_type_exit:
171  *  Free list of registered bitmap file types.
172  */
register_bitmap_file_type_exit(void)173 static void register_bitmap_file_type_exit(void)
174 {
175    BITMAP_TYPE_INFO *iter = bitmap_type_list, *next;
176 
177    while (iter) {
178       next = iter->next;
179       _AL_FREE(iter->ext);
180       _AL_FREE(iter);
181       iter = next;
182    }
183 
184    bitmap_type_list = NULL;
185 
186    /* If we are using a destructor, then we only want to prune the list
187     * down to valid modules. So we clean up as usual, but then reinstall
188     * the internal modules.
189     */
190    #ifdef ALLEGRO_USE_CONSTRUCTOR
191       _register_bitmap_file_type_init();
192    #endif
193 
194    _remove_exit_func(register_bitmap_file_type_exit);
195 }
196 
197 
198 
199 /* _register_bitmap_file_type_init:
200  *  Register built-in bitmap file types.
201  */
_register_bitmap_file_type_init(void)202 void _register_bitmap_file_type_init(void)
203 {
204    char buf[32];
205 
206    _add_exit_func(register_bitmap_file_type_exit,
207 		  "register_bitmap_file_type_exit");
208 
209    register_bitmap_file_type(uconvert_ascii("bmp", buf), load_bmp, save_bmp);
210    register_bitmap_file_type(uconvert_ascii("lbm", buf), load_lbm, NULL);
211    register_bitmap_file_type(uconvert_ascii("pcx", buf), load_pcx, save_pcx);
212    register_bitmap_file_type(uconvert_ascii("tga", buf), load_tga, save_tga);
213 }
214 
215 
216 
217 #ifdef ALLEGRO_USE_CONSTRUCTOR
218    CONSTRUCTOR_FUNCTION(static void bitmap_filetype_constructor(void));
219    DESTRUCTOR_FUNCTION(static void bitmap_filetype_destructor(void));
220 
221    /* bitmap_filetype_constructor:
222     *  Register bitmap filetype functions if this object file is linked
223     *  in. This isn't called if the load_bitmap() and save_bitmap()
224     *  functions aren't used in a program, thus saving a little space
225     *  in statically linked programs.
226     */
bitmap_filetype_constructor(void)227    static void bitmap_filetype_constructor(void)
228    {
229       _register_bitmap_file_type_init();
230    }
231 
232    /* bitmap_filetype_destructor:
233     *  Since we only want to destroy the whole list when we *actually*
234     *  quit, not just when allegro_exit() is called, we need to use a
235     *  destructor to accomplish this.
236     */
bitmap_filetype_destructor(void)237    static void bitmap_filetype_destructor(void)
238    {
239       BITMAP_TYPE_INFO *iter = bitmap_type_list, *next;
240 
241       while (iter) {
242          next = iter->next;
243          _AL_FREE(iter->ext);
244          _AL_FREE(iter);
245          iter = next;
246       }
247 
248       bitmap_type_list = NULL;
249 
250       _remove_exit_func(register_bitmap_file_type_exit);
251    }
252 #endif
253