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 // sprite with individual 32bit palette
10 /////////////////////////////////////////////////////////////////////////////
11 #include <stdio.h>
12 #include <string.h>
13 #include "globals.h"
14 #include "types.h"
15 #include "sprite.h"
16 /////////////////////////////////////////////////////////////////////////////
17 
18 
putsprite_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth)19 static void putsprite_(
20     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth
21 )
22 {
23     for(; h > 0; h--, dest += screenwidth)
24     {
25         register int lx = x;
26         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
27         linetab++;
28         while(lx < xmax)
29         {
30             register int count = *data++;
31             if(count == 0xFF)
32             {
33                 break;
34             }
35             lx += count;
36             if(lx >= xmax)
37             {
38                 break;
39             }
40             count = *data++;
41             if(!count)
42             {
43                 continue;
44             }
45             if((lx + count) <= xmin)
46             {
47                 lx += count;
48                 data += count;
49                 continue;
50             }
51             if(lx < xmin)
52             {
53                 int diff = lx - xmin;
54                 count += diff;
55                 data -= diff;
56                 lx = xmin;
57             }
58             if((lx + count) > xmax)
59             {
60                 count = xmax - lx;
61             }
62             for(; count > 0; count--)
63             {
64                 dest[lx++] = palette[*data++];
65             }
66             //u32pcpy(dest+lx, data, palette, count);
67             //lx+=count;
68             //data+=count;
69         }
70     }
71 }
72 
putsprite_flip_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth)73 static void putsprite_flip_(
74     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth
75 )
76 {
77     for(; h > 0; h--, dest += screenwidth)
78     {
79         register int lx = x;
80         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
81         linetab++;
82         while(lx > xmin)
83         {
84             register int count = *data++;
85             if(count == 0xFF)
86             {
87                 break;
88             }
89             lx -= count;
90             if(lx <= xmin)
91             {
92                 break;
93             }
94             count = *data++;
95             if(!count)
96             {
97                 continue;
98             }
99             if((lx - count) >= xmax)
100             {
101                 lx -= count;
102                 data += count;
103                 continue;
104             }
105             if(lx > xmax)
106             {
107                 int diff = (lx - xmax);
108                 count -= diff;
109                 data += diff;
110                 lx = xmax;
111             }
112             if((lx - count) < xmin)
113             {
114                 count = lx - xmin;
115             }
116             for(; count > 0; count--)
117             {
118                 dest[--lx] = palette[*data++];
119             }
120             //--lx;
121             //u32revpcpy(dest+lx, data, palette, count);
122             //lx-=count-1;
123             //data+=count;
124         }
125     }
126 }
127 
128 
129 //src high dest low
putsprite_blend_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth,unsigned (* blendfp)(unsigned,unsigned))130 static void putsprite_blend_(
131     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth,
132     unsigned (*blendfp)(unsigned, unsigned)
133 )
134 {
135     for(; h > 0; h--, dest += screenwidth)
136     {
137         register int lx = x;
138         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
139         linetab++;
140         while(lx < xmax)
141         {
142             register int count = *data++;
143             if(count == 0xFF)
144             {
145                 break;
146             }
147             lx += count;
148             if(lx >= xmax)
149             {
150                 break;
151             }
152             count = *data++;
153             if(!count)
154             {
155                 continue;
156             }
157             if((lx + count) <= xmin)
158             {
159                 lx += count;
160                 data += count;
161                 continue;
162             }
163             if(lx < xmin)
164             {
165                 int diff = lx - xmin;
166                 count += diff;
167                 data -= diff;
168                 lx = xmin;
169             }
170             if((lx + count) > xmax)
171             {
172                 count = xmax - lx;
173             }
174             for(; count > 0; count--, lx++)
175             {
176                 dest[lx] = blendfp(palette[*data++], dest[lx]);
177             }
178         }
179     }
180 }
181 
putsprite_blend_flip_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth,unsigned (* blendfp)(unsigned,unsigned))182 static void putsprite_blend_flip_(
183     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth,
184     unsigned (*blendfp)(unsigned, unsigned)
185 )
186 {
187     for(; h > 0; h--, dest += screenwidth)
188     {
189         register int lx = x;
190         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
191         linetab++;
192         while(lx > xmin)
193         {
194             register int count = *data++;
195             if(count == 0xFF)
196             {
197                 break;
198             }
199             lx -= count;
200             if(lx <= xmin)
201             {
202                 break;
203             }
204             count = *data++;
205             if(!count)
206             {
207                 continue;
208             }
209             if((lx - count) >= xmax)
210             {
211                 lx -= count;
212                 data += count;
213                 continue;
214             }
215             if(lx > xmax)
216             {
217                 int diff = (lx - xmax);
218                 count -= diff;
219                 data += diff;
220                 lx = xmax;
221             }
222             if((lx - count) < xmin)
223             {
224                 count = lx - xmin;
225             }
226             for(; count > 0; count--)
227             {
228                 --lx;
229                 dest[lx] = blendfp(palette[*data++], dest[lx]);
230             }
231         }
232     }
233 }
234 
235 //src high dest low
putsprite_mask_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth,int * masklinetab)236 static void putsprite_mask_(
237     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth,
238     int *masklinetab
239 )
240 {
241     for(; h > 0; h--, dest += screenwidth)
242     {
243         register int lx = x;
244         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
245         linetab++;
246         unsigned char *maskdata = ((unsigned char *)masklinetab) + (*masklinetab);
247         masklinetab++;
248         while(lx < xmax)
249         {
250             register int count = *data++;
251             maskdata++;
252             if(count == 0xFF)
253             {
254                 break;
255             }
256             lx += count;
257             if(lx >= xmax)
258             {
259                 break;
260             }
261             count = *data++;
262             maskdata++;
263             if(!count)
264             {
265                 continue;
266             }
267             if((lx + count) <= xmin)
268             {
269                 lx += count;
270                 data += count;
271                 maskdata += count;
272                 continue;
273             }
274             if(lx < xmin)
275             {
276                 int diff = lx - xmin;
277                 count += diff;
278                 data -= diff;
279                 maskdata -= diff;
280                 lx = xmin;
281             }
282             if((lx + count) > xmax)
283             {
284                 count = xmax - lx;
285             }
286             for(; count > 0; count--, lx++)
287             {
288                 dest[lx] = blend_channel32(palette[*data++], dest[lx], *maskdata++);
289             }
290         }
291     }
292 }
293 
putsprite_mask_flip_(unsigned * dest,int x,int xmin,int xmax,int * linetab,unsigned * palette,int h,int screenwidth,int * masklinetab)294 static void putsprite_mask_flip_(
295     unsigned *dest, int x, int xmin, int xmax, int *linetab, unsigned *palette, int h, int screenwidth,
296     int *masklinetab
297 )
298 {
299     for(; h > 0; h--, dest += screenwidth)
300     {
301         register int lx = x;
302         unsigned char *data = ((unsigned char *)linetab) + (*linetab);
303         linetab++;
304         unsigned char *maskdata = ((unsigned char *)masklinetab) + (*masklinetab);
305         masklinetab++;
306         while(lx > xmin)
307         {
308             register int count = *data++;
309             maskdata++;
310             if(count == 0xFF)
311             {
312                 break;
313             }
314             lx -= count;
315             if(lx <= xmin)
316             {
317                 break;
318             }
319             count = *data++;
320             maskdata++;
321             if(!count)
322             {
323                 continue;
324             }
325             if((lx - count) >= xmax)
326             {
327                 lx -= count;
328                 data += count;
329                 maskdata += count;
330                 continue;
331             }
332             if(lx > xmax)
333             {
334                 int diff = (lx - xmax);
335                 count -= diff;
336                 data += diff;
337                 maskdata += diff;
338                 lx = xmax;
339             }
340             if((lx - count) < xmin)
341             {
342                 count = lx - xmin;
343             }
344             for(; count > 0; count--)
345             {
346                 --lx;
347                 dest[lx] = blend_channel32(palette[*data++], dest[lx], *maskdata++);
348             }
349         }
350     }
351 }
352 
353 /////////////////////////////////////////////////////////////////////////////
354 
putsprite_x8p32(int x,int y,int is_flip,s_sprite * sprite,s_screen * screen,unsigned * remap,blend32fp blend)355 void putsprite_x8p32(
356     int x, int y, int is_flip, s_sprite *sprite, s_screen *screen,
357     unsigned *remap, blend32fp blend
358 )
359 {
360     int *linetab, *masklinetab = NULL;
361     int w, h;
362     unsigned *dest;
363     unsigned *m;
364     // Get screen size
365     int screenwidth = screen->width;
366     int xmin = useclip ? MAX(clipx1, 0) : 0,
367         xmax = useclip ? MIN(clipx2, screen->width) : screen->width,
368         ymin = useclip ? MAX(clipy1, 0) : 0,
369         ymax = useclip ? MIN(clipy2, screen->height) : screen->height;
370     // Adjust coords for centering
371     if(is_flip)
372     {
373         x += sprite->centerx;
374     }
375     else
376     {
377         x -= sprite->centerx;
378     }
379     y -= sprite->centery;
380     // Get sprite dimensions
381     w = sprite->width;
382     h = sprite->height;
383     // trivial clip all directions
384     if(is_flip)
385     {
386         if(x - w >= xmax)
387         {
388             return;
389         }
390         if(x <= xmin)
391         {
392             return;
393         }
394     }
395     else
396     {
397         if(x >= xmax)
398         {
399             return;
400         }
401         if((x + w) <= xmin)
402         {
403             return;
404         }
405     }
406     if(y >= ymax)
407     {
408         return;
409     }
410     if((y + h) <= ymin)
411     {
412         return;
413     }
414     // Init line table pointer
415     linetab = (int *)(sprite->data);
416     if(sprite->mask)
417     {
418         masklinetab = (int *)(sprite->mask->data);
419         //if(w!=sprite->mask->width) { printf("Wrong mask width. %i %i\n", w, sprite->mask->width); return; }
420         //if(h!=sprite->mask->height) { printf("Wrong mask height. %i %i\n", h, sprite->mask->height); return; }
421     }
422     // clip top
423     if(y < ymin)
424     {
425         int diff = y - ymin;
426         h += diff; // subtract from height
427         linetab -= diff; // add to linetab
428         masklinetab -= diff;
429         y = ymin; // add to y
430     }
431     // clip bottom
432     if((y + h) > ymax)
433     {
434         h = ymax - y;
435     }
436     // calculate destination pointer
437     dest = ((unsigned *)(screen->data)) + y * screenwidth;
438     if(remap)
439     {
440         m = remap;
441     }
442     else
443     {
444         m = (unsigned *)sprite->palette;
445     }
446     if(sprite->mask)
447     {
448         if(is_flip)
449         {
450             putsprite_mask_flip_ (dest, x, xmin, xmax, linetab, m, h, screenwidth, masklinetab);
451         }
452         else
453         {
454             putsprite_mask_      (dest, x, xmin, xmax, linetab, m, h, screenwidth, masklinetab);
455         }
456     }
457     else if(blend)
458     {
459         if(is_flip)
460         {
461             putsprite_blend_flip_(dest, x, xmin, xmax, linetab, m , h, screenwidth, blend);
462         }
463         else
464         {
465             putsprite_blend_     (dest, x, xmin, xmax  , linetab, m , h, screenwidth, blend);
466         }
467     }
468     else
469     {
470         if(is_flip)
471         {
472             putsprite_flip_      (dest, x, xmin, xmax, linetab, m , h, screenwidth);
473         }
474         else
475         {
476             putsprite_           (dest, x, xmin, xmax  , linetab, m , h, screenwidth);
477         }
478     }
479 }
480 
481 /////////////////////////////////////////////////////////////////////////////
482 
483