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