1 /*
2  * OpenBOR - http://www.LavaLit.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2011 OpenBOR Team
7  */
8 
9 // sprite with individual 32bit palette
10 /////////////////////////////////////////////////////////////////////////////
11 #include <stdio.h>
12 #include <string.h>
13 #include "types.h"
14 #include "sprite.h"
15 /////////////////////////////////////////////////////////////////////////////
16 
17 
putsprite_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth)18 static void putsprite_(
19   unsigned *dest, int x, int *linetab, unsigned *palette, int h, int screenwidth
20 ) {
21   for(; h > 0; h--, dest += screenwidth) {
22 	register int lx = x;
23 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
24 	while(lx < screenwidth) {
25 	  register int count = *data++;
26 	  if(count == 0xFF) break;
27 	  lx += count;
28 	  if(lx >= screenwidth) break;
29 	  count = *data++;
30 	  if(!count) continue;
31 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
32 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
33 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
34 	  //for(; count > 0; count--)  dest[lx++] = palette[*data++];
35 	  u32pcpy(dest+lx, data, palette, count);
36 	  lx+=count;
37 	  data+=count;
38 	}
39   }
40 }
41 
putsprite_flip_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth)42 static void putsprite_flip_(
43   unsigned *dest, int x, int *linetab, unsigned* palette, int h, int screenwidth
44 ) {
45   for(; h > 0; h--, dest += screenwidth) {
46 	register int lx = x;
47 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
48 	while(lx > 0) {
49 	  register int count = *data++;
50 	  if(count == 0xFF) break;
51 	  lx -= count;
52 	  if(lx <= 0) break;
53 	  count = *data++;
54 	  if(!count) continue;
55 	  if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
56 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
57 	  if((lx - count) < 0) { count = lx; }
58 	  //for(; count > 0; count--) dest[--lx] = palette[*data++];
59 	  --lx;
60 	  u32revpcpy(dest+lx, data, palette, count);
61 	  lx-=count-1;
62 	  data+=count;
63 	}
64   }
65 }
66 
67 
68 //src high dest low
putsprite_blend_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth,unsigned (* blendfp)(unsigned,unsigned))69 static void putsprite_blend_(
70   unsigned *dest, int x, int *linetab, unsigned* palette, int h, int screenwidth,
71   unsigned (*blendfp)(unsigned, unsigned)
72 ) {
73   for(; h > 0; h--, dest += screenwidth) {
74 	register int lx = x;
75 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
76 	while(lx < screenwidth) {
77 	  register int count = *data++;
78 	  if(count == 0xFF) break;
79 	  lx += count;
80 	  if(lx >= screenwidth) break;
81 	  count = *data++;
82 	  if(!count) continue;
83 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
84 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
85 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
86 	  for(; count > 0; count--, lx++)
87 	  {
88 		 dest[lx] = blendfp(palette[*data++], dest[lx]);
89 	  }
90 	}
91   }
92 }
93 
putsprite_blend_flip_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth,unsigned (* blendfp)(unsigned,unsigned))94 static void putsprite_blend_flip_(
95   unsigned *dest, int x, int *linetab, unsigned * palette, int h, int screenwidth,
96   unsigned (*blendfp)(unsigned, unsigned)
97 ) {
98   for(; h > 0; h--, dest += screenwidth) {
99 	register int lx = x;
100 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
101 	while(lx > 0) {
102 	  register int count = *data++;
103 	  if(count == 0xFF) break;
104 	  lx -= count;
105 	  if(lx <= 0) break;
106 	  count = *data++;
107 	  if(!count) continue;
108 	  if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
109 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
110 	  if((lx - count) < 0) { count = lx; }
111 	  for(; count > 0; count--)
112 	  {   --lx;
113 		  dest[lx] = blendfp(palette[*data++], dest[lx]);
114 	  }
115 	}
116   }
117 }
118 
119 //src high dest low
putsprite_mask_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth,int * masklinetab)120 static void putsprite_mask_(
121   unsigned *dest, int x, int *linetab, unsigned* palette, int h, int screenwidth,
122   int* masklinetab
123 ) {
124   for(; h > 0; h--, dest += screenwidth) {
125 	register int lx = x;
126 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
127 	unsigned char *maskdata = ((unsigned char*)masklinetab) + (*masklinetab); masklinetab++;
128 	while(lx < screenwidth) {
129 	  register int count = *data++; maskdata++;
130 	  if(count == 0xFF) break;
131 	  lx += count;
132 	  if(lx >= screenwidth) break;
133 	  count = *data++; maskdata++;
134 	  if(!count) continue;
135 	  if((lx + count) <= 0) { lx += count; data += count; maskdata += count; continue; }
136 	  if(lx < 0) { count += lx; data -= lx; maskdata -= lx; lx = 0; }
137 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
138 	  for(; count > 0; count--, lx++)
139 	  {
140 		 dest[lx] = blend_channel32(palette[*data++], dest[lx], *maskdata++);
141 	  }
142 	}
143   }
144 }
145 
putsprite_mask_flip_(unsigned * dest,int x,int * linetab,unsigned * palette,int h,int screenwidth,int * masklinetab)146 static void putsprite_mask_flip_(
147   unsigned *dest, int x, int *linetab, unsigned * palette, int h, int screenwidth,
148   int *masklinetab
149 ) {
150   for(; h > 0; h--, dest += screenwidth) {
151 	register int lx = x;
152 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
153 	unsigned char *maskdata = ((unsigned char*)masklinetab) + (*masklinetab); masklinetab++;
154 	while(lx > 0) {
155 	  register int count = *data++; maskdata++;
156 	  if(count == 0xFF) break;
157 	  lx -= count;
158 	  if(lx <= 0) break;
159 	  count = *data++; maskdata++;
160 	  if(!count) continue;
161 	  if((lx - count) >= screenwidth) { lx -= count; data += count; maskdata += count; continue; }
162 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; maskdata += diff; lx = screenwidth; }
163 	  if((lx - count) < 0) { count = lx; }
164 	  for(; count > 0; count--)
165 	  {   --lx;
166 		  dest[lx] = blend_channel32(palette[*data++], dest[lx], *maskdata++);
167 	  }
168 	}
169   }
170 }
171 
172 /////////////////////////////////////////////////////////////////////////////
173 
putsprite_x8p32(int x,int y,int is_flip,s_sprite * sprite,s_screen * screen,unsigned * remap,blend32fp blend)174 void putsprite_x8p32(
175   int x, int y, int is_flip, s_sprite *sprite, s_screen *screen,
176   unsigned *remap, blend32fp blend
177 ) {
178   int *linetab, *masklinetab = NULL;
179   int w, h;
180   unsigned *dest;
181   unsigned * m;
182   // Get screen size
183   int screenwidth = screen->width;
184   int screenheight = screen->height;
185   // Adjust coords for centering
186   if(is_flip) x += sprite->centerx;
187   else x -= sprite->centerx;
188   y -= sprite->centery;
189   // Get sprite dimensions
190   w = sprite->width;
191   h = sprite->height;
192   // trivial clip all directions
193   if(is_flip)
194   {
195 	  if(x-w >= screenwidth) return;
196 	  if(x <= 0) return;
197   }
198   else
199   {
200 	  if(x >= screenwidth) return;
201 	  if((x+w) <= 0) return;
202   }
203   if(y >= screenheight) return;
204   if((y+h) <= 0) return;
205   // Init line table pointer
206   linetab = (int*)(sprite->data);
207   if(sprite->mask) {
208 	masklinetab = (int*)(sprite->mask->data);
209 	//if(w!=sprite->mask->width) { printf("Wrong mask width. %i %i\n", w, sprite->mask->width); return; }
210 	//if(h!=sprite->mask->height) { printf("Wrong mask height. %i %i\n", h, sprite->mask->height); return; }
211   }
212   // clip top
213   if(y < 0) {
214 	h += y; // subtract from height
215 	linetab -= y; // add to linetab
216 	y = 0; // add to y
217   }
218   // clip bottom
219   if((y+h) > screenheight) {
220 	h = screenheight - y;
221   }
222   // calculate destination pointer
223   dest = ((unsigned*)(screen->data)) + y*screenwidth;
224   if(remap) m = remap;
225   else      m = (unsigned*)sprite->palette;
226   if(sprite->mask) {
227 	if(is_flip) putsprite_mask_flip_ (dest, x, linetab, m, h, screenwidth, masklinetab);
228 	else        putsprite_mask_      (dest, x, linetab, m, h, screenwidth, masklinetab);
229   } else if(blend) {
230 	if(is_flip) putsprite_blend_flip_(dest, x, linetab, m , h, screenwidth, blend);
231 	else        putsprite_blend_     (dest, x  , linetab, m , h, screenwidth, blend);
232   } else {
233 	if(is_flip) putsprite_flip_      (dest, x, linetab, m , h, screenwidth);
234 	else        putsprite_           (dest, x  , linetab, m , h, screenwidth);
235   }
236 }
237 
238 /////////////////////////////////////////////////////////////////////////////
239 
240