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