1 /*
2  * OpenBOR - http://www.chronocrash.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2014 OpenBOR Team
7  */
8 
9 // Simple bitmap code. Not fast, but useful nonetheless...
10 // 25-jan-2003
11 
12 #include <stdio.h>
13 #include <string.h>
14 #include <stddef.h>
15 #include "globals.h"
16 #include "types.h"
17 
18 #define		TRANS_INDEX		0x00
19 
allocbitmap(int width,int height,int format)20 s_bitmap *allocbitmap(int width, int height, int format)
21 {
22     s_bitmap *b;
23     ptrdiff_t psize, extrab;
24     if(width * height == 0)
25     {
26         return NULL;
27     }
28     psize = width * height * pixelbytes[(int)format];
29     extrab = (4 - psize % 4) % 4;
30     if(format == PIXEL_x8)
31     {
32         b = (s_bitmap *)malloc(sizeof(s_bitmap) + psize + extrab + PAL_BYTES);
33     }
34     else
35     {
36         b = (s_bitmap *)malloc(sizeof(s_bitmap) + psize);
37     }
38     if(b)
39     {
40         b->width = width;
41         b->height = height;
42         b->pixelformat = format;
43         b->magic = bitmap_magic;
44         b->clipped_x_offset = 0;
45         b->clipped_y_offset = 0;
46         b->clipped_width = width;
47         b->clipped_height = height;
48         if(format == PIXEL_x8)
49         {
50             b->palette = ((unsigned char *)b->data) + psize + extrab;
51         }
52         else
53         {
54             b->palette = NULL;
55         }
56     }
57     return b;
58 }
59 
freebitmap(s_bitmap * bitmap)60 void freebitmap(s_bitmap *bitmap)
61 {
62     if(bitmap != NULL)
63     {
64         free(bitmap);
65         bitmap = NULL;
66     }
67 }
68 
69 // Sluggish getbitmap function. Should be redone in ASM.
getbitmap(int x,int y,int width,int height,s_bitmap * bitmap,s_screen * screen)70 void getbitmap(int x, int y, int width, int height, s_bitmap *bitmap, s_screen *screen)
71 {
72 
73     int s, d;
74     //int i;
75     int j;
76 
77     // Clip width and height
78     if(x < 0)
79     {
80         width += x;
81         x = 0;
82     }
83     if(y < 0)
84     {
85         height += y;
86         y = 0;
87     }
88     if(x + width > screen->width)
89     {
90         width = screen->width - x;
91     }
92     if(y + height > screen->height)
93     {
94         height = screen->height - y;
95     }
96     if(width <= 0 || height <= 0)
97     {
98         bitmap->width = 0;
99         bitmap->height = 0;
100         return;
101     }
102 
103     bitmap->width = bitmap->clipped_width = width;
104     bitmap->height = bitmap->clipped_height = height;
105     bitmap->clipped_x_offset = 0;
106     bitmap->clipped_y_offset = 0;
107 
108     d = 0;
109     for(j = 0; j < height; j++)
110     {
111         s = x + (y + j) * screen->width;
112         memcpy(((char *)bitmap->data) + d, ((char *)screen->data) + s, width);
113         d += width;
114         /*
115         for(i=0; i<width; i++){
116         	bitmap->data[d] = screen->data[s];
117         	++d;
118         	++s;
119         }
120         */
121     }
122 }
123 
124 
125 
126 // Clipped putbitmap. Slow.
putbitmap(int x,int y,s_bitmap * bitmap,s_screen * screen)127 void putbitmap(int x, int y, s_bitmap *bitmap, s_screen *screen)
128 {
129     int skipleft = 0;
130     int skiptop = 0;
131     int width = bitmap->width;
132     int height = bitmap->height;
133     int s, d;
134     int i;
135 
136     // Clip width and height
137     if(x < 0)
138     {
139         skipleft = -x;
140         width -= skipleft;
141         x = 0;
142     }
143     if(y < 0)
144     {
145         skiptop = -y;
146         height -= skiptop;
147         y = 0;
148     }
149     if(x + width > screen->width)
150     {
151         width = screen->width - x;
152     }
153     if(y + height > screen->height)
154     {
155         height = screen->height - y;
156     }
157     if(width <= 0 || height <= 0)
158     {
159         return;
160     }
161 
162     d = (y * screen->width) + x;
163 
164     do
165     {
166         s = skiptop * bitmap->width + skipleft;
167         ++skiptop;
168         for(i = 0; i < width; i++)
169         {
170             screen->data[d] = bitmap->data[s];
171             ++d;
172             ++s;
173         }
174         d += screen->width;
175         d -= width;
176     }
177     while(--height);
178 }
179 
180 
181 
182 
183 // Flip horizontally
flipbitmap(s_bitmap * bitmap)184 void flipbitmap(s_bitmap *bitmap)
185 {
186     int x, xo, y;
187     unsigned char t;
188     int xsize = bitmap->width;
189     int ysize = bitmap->height;
190 
191     for(y = 0; y < ysize; y++)
192     {
193         for(x = 0, xo = xsize - 1; x < xsize / 2; x++, xo--)
194         {
195             t = bitmap->data[y * xsize + x];
196             bitmap->data[y * xsize + x] = bitmap->data[y * xsize + xo];
197             bitmap->data[y * xsize + xo] = t;
198         }
199     }
200 }
201 
202 
203 
204 
205 
206 // Clipbitmap: cuts off transparent edges to optimize a bitmap.
clipbitmap(s_bitmap * bitmap,int * clip_left,int * clip_right,int * clip_top,int * clip_bottom)207 void clipbitmap(s_bitmap *bitmap, int *clip_left, int *clip_right, int *clip_top, int *clip_bottom)
208 {
209 
210     int x, y;
211     int clip, clear;
212     int xsize = bitmap->width;
213     int ysize = bitmap->height;
214     int fullwidth = bitmap->width;
215     int top_clipmove = 0;
216     int left_clipmove = 0;
217     int bottom_clipmove = 0;
218     int right_clipmove = 0;
219 
220 
221 
222     // Determine size of empty top
223     clip = 0;
224     for(y = 0; y < ysize; y++)
225     {
226         clear = 1;
227         for(x = 0; x < xsize && clear; x++)
228         {
229             if(bitmap->data[y * xsize + x] != TRANS_INDEX)
230             {
231                 clear = 0;
232             }
233         }
234         if(clear)
235         {
236             ++clip;
237         }
238         else
239         {
240             break;
241         }
242     }
243 
244     if(clip)
245     {
246         // "Cut off" empty top
247         ysize -= clip;
248         if(ysize < 1)
249         {
250             // If nothing is left of the bitmap, return...
251             if(clip_left)
252             {
253                 *clip_left = 0;
254             }
255             if(clip_right)
256             {
257                 *clip_right = 0;
258             }
259             if(clip_top)
260             {
261                 *clip_top = 0;
262             }
263             if(clip_bottom)
264             {
265                 *clip_bottom = 0;
266             }
267             bitmap->clipped_width = 0;
268             bitmap->clipped_height = 0;
269             return;
270         }
271         bitmap->clipped_y_offset = clip;
272         top_clipmove = clip;
273     }
274 
275 
276 
277     // Determine size of empty bottom
278     clip = 0;
279     for(y = bitmap->height - 1; y >= top_clipmove; y--)
280     {
281         clear = 1;
282         for(x = 0; x < xsize && clear; x++)
283         {
284             if(bitmap->data[y * xsize + x] != TRANS_INDEX)
285             {
286                 clear = 0;
287             }
288         }
289         if(clear)
290         {
291             ++clip;
292         }
293         else
294         {
295             break;
296         }
297     }
298 
299     // "Cut off" empty bottom
300     ysize -= clip;
301     bitmap->clipped_height = ysize;
302     bottom_clipmove = clip;
303 
304 
305     // Determine size of empty left side
306     clip = 2000000000;
307     for(y = top_clipmove; y < ysize + top_clipmove; y++)
308     {
309         clear = 0;
310         for(x = 0; x < xsize; x++)
311         {
312             if(bitmap->data[y * xsize + x] != TRANS_INDEX)
313             {
314                 break;
315             }
316             ++clear;
317         }
318         if(clear < clip)
319         {
320             clip = clear;
321         }
322     }
323 
324     // "Cut off" empty pixels on the left side
325     if(clip)
326     {
327         xsize -= clip;
328         bitmap->clipped_width = xsize;
329         bitmap->clipped_x_offset = clip;
330         left_clipmove = clip;
331     }
332 
333     // Determine size of empty right side
334     clip = 2000000000;
335     for(y = top_clipmove; y < ysize + top_clipmove; y++)
336     {
337         clear = 0;
338         for(x = fullwidth - 1; x >= left_clipmove; x--)
339         {
340             if(bitmap->data[y * fullwidth + x] != TRANS_INDEX)
341             {
342                 break;
343             }
344             ++clear;
345         }
346         if(clear < clip)
347         {
348             clip = clear;
349         }
350     }
351 
352     // "Cut off" empty pixels on the right side
353     if(clip)
354     {
355         xsize -= clip;
356         bitmap->clipped_width = xsize;
357         right_clipmove = clip;
358     }
359 
360     if(clip_left)
361     {
362         *clip_left = left_clipmove;
363     }
364     if(clip_right)
365     {
366         *clip_right = right_clipmove;
367     }
368     if(clip_top)
369     {
370         *clip_top = top_clipmove;
371     }
372     if(clip_bottom)
373     {
374         *clip_bottom = bottom_clipmove;
375     }
376 }
377 
378 
379 
380