1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Convert between memory and video bitmap types.
12 *
13 * See LICENSE.txt for copyright information.
14 */
15
16
17 #include "allegro5/allegro.h"
18 #include "allegro5/internal/aintern.h"
19 #include "allegro5/internal/aintern_bitmap.h"
20 #include "allegro5/internal/aintern_exitfunc.h"
21 #include "allegro5/internal/aintern_shader.h"
22 #include "allegro5/internal/aintern_system.h"
23 #include "allegro5/internal/aintern_vector.h"
24
25 ALLEGRO_DEBUG_CHANNEL("bitmap")
26
27
28 /* Global list of MEMORY bitmaps with ALLEGRO_CONVERT_BITMAP flag. */
29 struct BITMAP_CONVERSION_LIST {
30 ALLEGRO_MUTEX *mutex;
31 _AL_VECTOR bitmaps;
32 };
33
34
35 static struct BITMAP_CONVERSION_LIST convert_bitmap_list;
36
37
cleanup_convert_bitmap_list(void)38 static void cleanup_convert_bitmap_list(void)
39 {
40 _al_vector_free(&convert_bitmap_list.bitmaps);
41 al_destroy_mutex(convert_bitmap_list.mutex);
42 }
43
44
45 /* This is called in al_install_system. Exit functions are called in
46 * al_uninstall_system.
47 */
_al_init_convert_bitmap_list(void)48 void _al_init_convert_bitmap_list(void)
49 {
50 convert_bitmap_list.mutex = al_create_mutex_recursive();
51 _al_vector_init(&convert_bitmap_list.bitmaps, sizeof(ALLEGRO_BITMAP *));
52 _al_add_exit_func(cleanup_convert_bitmap_list,
53 "cleanup_convert_bitmap_list");
54 }
55
56
_al_register_convert_bitmap(ALLEGRO_BITMAP * bitmap)57 void _al_register_convert_bitmap(ALLEGRO_BITMAP *bitmap)
58 {
59 int bitmap_flags = al_get_bitmap_flags(bitmap);
60 if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP))
61 return;
62 if (bitmap_flags & ALLEGRO_CONVERT_BITMAP) {
63 ALLEGRO_BITMAP **back;
64 al_lock_mutex(convert_bitmap_list.mutex);
65 back = _al_vector_alloc_back(&convert_bitmap_list.bitmaps);
66 *back = bitmap;
67 al_unlock_mutex(convert_bitmap_list.mutex);
68 }
69 }
70
71
_al_unregister_convert_bitmap(ALLEGRO_BITMAP * bitmap)72 void _al_unregister_convert_bitmap(ALLEGRO_BITMAP *bitmap)
73 {
74 int bitmap_flags = al_get_bitmap_flags(bitmap);
75 if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP))
76 return;
77 if (bitmap_flags & ALLEGRO_CONVERT_BITMAP) {
78 al_lock_mutex(convert_bitmap_list.mutex);
79 _al_vector_find_and_delete(&convert_bitmap_list.bitmaps, &bitmap);
80 al_unlock_mutex(convert_bitmap_list.mutex);
81 }
82 }
83
84
swap_bitmaps(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP * other)85 static void swap_bitmaps(ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP *other)
86 {
87 ALLEGRO_BITMAP temp;
88 _AL_LIST_ITEM *bitmap_dtor_item = bitmap->dtor_item;
89 _AL_LIST_ITEM *other_dtor_item = other->dtor_item;
90 ALLEGRO_DISPLAY *bitmap_display, *other_display;
91
92 _al_unregister_convert_bitmap(bitmap);
93 _al_unregister_convert_bitmap(other);
94
95 if (other->shader)
96 _al_unregister_shader_bitmap(other->shader, other);
97 if (bitmap->shader)
98 _al_unregister_shader_bitmap(bitmap->shader, bitmap);
99
100 temp = *bitmap;
101 *bitmap = *other;
102 *other = temp;
103
104 /* Re-associate the destructors back, as they are tied to the object
105 * pointers.
106 */
107 bitmap->dtor_item = bitmap_dtor_item;
108 other->dtor_item = other_dtor_item;
109
110 bitmap_display = _al_get_bitmap_display(bitmap);
111 other_display = _al_get_bitmap_display(other);
112
113 /* We are basically done already. Except we now have to update everything
114 * possibly referencing any of the two bitmaps.
115 */
116
117 if (bitmap_display && !other_display) {
118 /* This means before the swap, other was the display bitmap, and we
119 * now should replace it with the swapped pointer.
120 */
121 ALLEGRO_BITMAP **back;
122 int pos = _al_vector_find(&bitmap_display->bitmaps, &other);
123 ASSERT(pos >= 0);
124 back = _al_vector_ref(&bitmap_display->bitmaps, pos);
125 *back = bitmap;
126 }
127
128 if (other_display && !bitmap_display) {
129 ALLEGRO_BITMAP **back;
130 int pos = _al_vector_find(&other_display->bitmaps, &bitmap);
131 ASSERT(pos >= 0);
132 back = _al_vector_ref(&other_display->bitmaps, pos);
133 *back = other;
134 }
135
136 if (other->shader)
137 _al_register_shader_bitmap(other->shader, other);
138 if (bitmap->shader)
139 _al_register_shader_bitmap(bitmap->shader, bitmap);
140
141 _al_register_convert_bitmap(bitmap);
142 _al_register_convert_bitmap(other);
143
144 if (bitmap->vt && bitmap->vt->bitmap_pointer_changed)
145 bitmap->vt->bitmap_pointer_changed(bitmap, other);
146
147 if (other->vt && other->vt->bitmap_pointer_changed)
148 other->vt->bitmap_pointer_changed(other, bitmap);
149 }
150
151
152 /* Function: al_convert_bitmap
153 */
al_convert_bitmap(ALLEGRO_BITMAP * bitmap)154 void al_convert_bitmap(ALLEGRO_BITMAP *bitmap)
155 {
156 ALLEGRO_BITMAP *clone;
157 int bitmap_flags = al_get_bitmap_flags(bitmap);
158 int new_bitmap_flags = al_get_new_bitmap_flags();
159 bool want_memory = (new_bitmap_flags & ALLEGRO_MEMORY_BITMAP) != 0;
160 bool clone_memory;
161 ALLEGRO_BITMAP *target_bitmap;
162
163 bitmap_flags &= ~_ALLEGRO_INTERNAL_OPENGL;
164
165 /* If a cloned bitmap would be identical, we can just do nothing. */
166 if (al_get_bitmap_format(bitmap) == al_get_new_bitmap_format() &&
167 bitmap_flags == new_bitmap_flags &&
168 _al_get_bitmap_display(bitmap) == al_get_current_display()) {
169 return;
170 }
171
172 if (bitmap->parent) {
173 al_convert_bitmap(bitmap->parent);
174 return;
175 }
176 else {
177 clone = al_clone_bitmap(bitmap);
178 }
179
180 if (!clone) {
181 return;
182 }
183
184 clone_memory = (al_get_bitmap_flags(clone) & ALLEGRO_MEMORY_BITMAP) != 0;
185
186 if (clone_memory != want_memory) {
187 /* We couldn't convert. */
188 al_destroy_bitmap(clone);
189 return;
190 }
191
192 swap_bitmaps(bitmap, clone);
193
194 /* Preserve bitmap state. */
195 bitmap->cl = clone->cl;
196 bitmap->ct = clone->ct;
197 bitmap->cr_excl = clone->cr_excl;
198 bitmap->cb_excl = clone->cb_excl;
199 bitmap->transform = clone->transform;
200 bitmap->inverse_transform = clone->inverse_transform;
201 bitmap->inverse_transform_dirty = clone->inverse_transform_dirty;
202
203 /* Memory bitmaps do not support custom projection transforms,
204 * so reset it to the orthographic transform. */
205 if (new_bitmap_flags & ALLEGRO_MEMORY_BITMAP) {
206 al_identity_transform(&bitmap->proj_transform);
207 al_orthographic_transform(&bitmap->proj_transform, 0, 0, -1.0, bitmap->w, bitmap->h, 1.0);
208 } else {
209 bitmap->proj_transform = clone->proj_transform;
210 }
211
212 /* If we just converted this bitmap, and the backing bitmap is the same
213 * as the target's backing bitmap, then the viewports and transformations
214 * will be messed up. Detect this, and just re-call al_set_target_bitmap
215 * on the current target. */
216 target_bitmap = al_get_target_bitmap();
217 if (target_bitmap) {
218 ALLEGRO_BITMAP *target_parent =
219 target_bitmap->parent ? target_bitmap->parent : target_bitmap;
220 if (bitmap == target_parent || bitmap->parent == target_parent) {
221 al_set_target_bitmap(target_bitmap);
222 }
223 }
224
225 al_destroy_bitmap(clone);
226 }
227
228
229 /* Function: al_convert_memory_bitmaps
230 */
al_convert_memory_bitmaps(void)231 void al_convert_memory_bitmaps(void)
232 {
233 ALLEGRO_STATE backup;
234 ALLEGRO_DISPLAY *display = al_get_current_display();
235 _AL_VECTOR copy;
236 size_t i;
237 if (!display) return;
238
239 al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS);
240
241 al_lock_mutex(convert_bitmap_list.mutex);
242
243 _al_vector_init(©, sizeof(ALLEGRO_BITMAP *));
244 for (i = 0; i < _al_vector_size(&convert_bitmap_list.bitmaps); i++) {
245 ALLEGRO_BITMAP **bptr, **bptr2;
246 bptr = _al_vector_ref(&convert_bitmap_list.bitmaps, i);
247 bptr2 = _al_vector_alloc_back(©);
248 *bptr2 = *bptr;
249 }
250 _al_vector_free(&convert_bitmap_list.bitmaps);
251 _al_vector_init(&convert_bitmap_list.bitmaps, sizeof(ALLEGRO_BITMAP *));
252 for (i = 0; i < _al_vector_size(©); i++) {
253 ALLEGRO_BITMAP **bptr;
254 int flags;
255 bptr = _al_vector_ref(©, i);
256 flags = al_get_bitmap_flags(*bptr);
257 flags &= ~ALLEGRO_MEMORY_BITMAP;
258 al_set_new_bitmap_flags(flags);
259 al_set_new_bitmap_format(al_get_bitmap_format(*bptr));
260
261 ALLEGRO_DEBUG("converting memory bitmap %p to display bitmap\n", *bptr);
262
263 al_convert_bitmap(*bptr);
264 }
265
266 _al_vector_free(©);
267
268 al_unlock_mutex(convert_bitmap_list.mutex);
269
270 al_restore_state(&backup);
271 }
272
273
274 /* Converts a memory bitmap to a display bitmap preserving its contents.
275 * The created bitmap belongs to the current display.
276 *
277 * If this is called for a sub-bitmap, the parent also is converted.
278 */
_al_convert_to_display_bitmap(ALLEGRO_BITMAP * bitmap)279 void _al_convert_to_display_bitmap(ALLEGRO_BITMAP *bitmap)
280 {
281 ALLEGRO_STATE backup;
282 int bitmap_flags = al_get_bitmap_flags(bitmap);
283 /* Do nothing if it is a display bitmap already. */
284 if (!(bitmap_flags & ALLEGRO_MEMORY_BITMAP))
285 return;
286
287 ALLEGRO_DEBUG("converting memory bitmap %p to display bitmap\n", bitmap);
288
289 al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS);
290 al_set_new_bitmap_flags(bitmap_flags & ~ALLEGRO_MEMORY_BITMAP);
291 al_set_new_bitmap_format(al_get_bitmap_format(bitmap));
292 al_convert_bitmap(bitmap);
293 al_restore_state(&backup);
294 }
295
296
297 /* Converts a display bitmap to a memory bitmap preserving its contents.
298 * If this is called for a sub-bitmap, the parent also is converted.
299 */
_al_convert_to_memory_bitmap(ALLEGRO_BITMAP * bitmap)300 void _al_convert_to_memory_bitmap(ALLEGRO_BITMAP *bitmap)
301 {
302 ALLEGRO_STATE backup;
303 int bitmap_flags = al_get_bitmap_flags(bitmap);
304 /* Do nothing if it is a memory bitmap already. */
305 if (bitmap_flags & ALLEGRO_MEMORY_BITMAP)
306 return;
307
308 ALLEGRO_DEBUG("converting display bitmap %p to memory bitmap\n", bitmap);
309
310 al_store_state(&backup, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS);
311 al_set_new_bitmap_flags((bitmap_flags & ~ALLEGRO_VIDEO_BITMAP) | ALLEGRO_MEMORY_BITMAP);
312 al_set_new_bitmap_format(al_get_bitmap_format(bitmap));
313 al_convert_bitmap(bitmap);
314 al_restore_state(&backup);
315 }
316
317
318 /* vim: set ts=8 sts=3 sw=3 et: */
319