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 /////////////////////////////////////////////////////////////////////////////
10 /*#include <stdio.h>
11 #include <string.h>*/
12 #include "globals.h"
13 #include "types.h"
14 #include "sprite.h"
15 #include "transform.h"
16 /////////////////////////////////////////////////////////////////////////////
17 
18 
putsprite_(unsigned char * dest,int x,int * linetab,int h,int screenwidth)19 static void putsprite_(
20   unsigned char *dest, int x, int *linetab, int h, int screenwidth
21 ) {
22   for(; h > 0; h--, dest += screenwidth) {
23 	register int lx = x;
24 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
25 	while(lx < screenwidth) {
26 	  register int count = *data++;
27 	  if(count == 0xFF) break;
28 	  lx += count;
29 	  if(lx >= screenwidth) break;
30 	  count = *data++;
31 	  if(!count) continue;
32 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
33 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
34 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
35 	  memcpy(dest+lx, data, count);
36 	  data+=count;lx+=count;
37 	}
38   }
39 }
40 
putsprite_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth)41 static void putsprite_flip_(
42   unsigned char *dest, int x, int *linetab, 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] = *data++;
58 	  lx--;
59 	  u8revcpy(dest+lx, data, count);
60 	  lx-=count-1;
61 	  data+=count;
62 	}
63   }
64 }
65 
putsprite_remap_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap)66 static void putsprite_remap_(
67   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
68   unsigned char *remap
69 ) {
70   for(; h > 0; h--, dest += screenwidth) {
71 	register int lx = x;
72 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
73 	while(lx < screenwidth) {
74 	  register int count = *data++;
75 	  if(count == 0xFF) break;
76 	  lx += count;
77 	  if(lx >= screenwidth) break;
78 	  count = *data++;
79 	  if(!count) continue;
80 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
81 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
82 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
83 	  //for(; count > 0; count--) dest[lx++] = remap[((int)(*data++))&0xFF];
84 	  u8pcpy(dest+lx, data, remap, count);
85 	  lx+=count;
86 	  data+=count;
87 	}
88   }
89 }
90 
putsprite_remap_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap)91 static void putsprite_remap_flip_(
92   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
93   unsigned char *remap
94 ) {
95   for(; h > 0; h--, dest += screenwidth) {
96 	register int lx = x;
97 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
98 	while(lx > 0) {
99 	  register int count = *data++;
100 	  if(count == 0xFF) break;
101 	  lx -= count;
102 	  if(lx <= 0) break;
103 	  count = *data++;
104 	  if(!count) continue;
105 	  if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
106 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
107 	  if((lx - count) < 0) { count = lx; }
108 	  //for(; count > 0; count--) dest[--lx] = remap[((int)(*data++))&0xFF];
109 	  lx--;
110 	  u8revpcpy(dest+lx, data, remap, count);
111 	  lx-=count-1;
112 	  data+=count;
113 	}
114   }
115 }
116 
117 //src high dest low
putsprite_remapblend_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)118 static void putsprite_remapblend_(
119   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
120   unsigned char*remap, unsigned char *blend
121 ) {
122   for(; h > 0; h--, dest += screenwidth) {
123 	register int lx = x;
124 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
125 	while(lx < screenwidth) {
126 	  register int count = *data++;
127 	  if(count == 0xFF) break;
128 	  lx += count;
129 	  if(lx >= screenwidth) break;
130 	  count = *data++;
131 	  if(!count) continue;
132 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
133 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
134 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
135 	  for(; count > 0; count--) { dest[lx] = blend[(remap[(((int)(*data++))&0xFF)]<<8)|dest[lx]]; lx++; }
136 	}
137   }
138 }
139 
putsprite_remapblend_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)140 static void putsprite_remapblend_flip_(
141   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
142   unsigned char* remap, unsigned char *blend
143 ) {
144   for(; h > 0; h--, dest += screenwidth) {
145 	register int lx = x;
146 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
147 	while(lx > 0) {
148 	  register int count = *data++;
149 	  if(count == 0xFF) break;
150 	  lx -= count;
151 	  if(lx <= 0) break;
152 	  count = *data++;
153 	  if(!count) continue;
154 	  if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
155 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
156 	  if((lx - count) < 0) { count = lx; }
157 	  for(; count > 0; count--) { --lx; dest[lx] = blend[(remap[(((int)(*data++))&0xFF)]<<8)|dest[lx]]; }
158 	}
159   }
160 }
161 
putsprite_blend_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * blend)162 static void putsprite_blend_(
163   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
164   unsigned char *blend
165 ) {
166   for(; h > 0; h--, dest += screenwidth) {
167 	register int lx = x;
168 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
169 	while(lx < screenwidth) {
170 	  register int count = *data++;
171 	  if(count == 0xFF) break;
172 	  lx += count;
173 	  if(lx >= screenwidth) break;
174 	  count = *data++;
175 	  if(!count) continue;
176 	  if((lx + count) <= 0) { lx += count; data += count; continue; }
177 	  if(lx < 0) { count += lx; data -= lx; lx = 0; }
178 	  if((lx + count) > screenwidth) { count = screenwidth - lx; }
179 	  for(; count > 0; count--) { dest[lx] = blend[((((int)(*data++))&0xFF)<<8)|dest[lx]]; lx++; }
180 	}
181   }
182 }
183 
putsprite_blend_flip_(unsigned char * dest,int x,int * linetab,int h,int screenwidth,unsigned char * blend)184 static void putsprite_blend_flip_(
185   unsigned char *dest, int x, int *linetab, int h, int screenwidth,
186   unsigned char *blend
187 ) {
188   for(; h > 0; h--, dest += screenwidth) {
189 	register int lx = x;
190 	unsigned char *data = ((unsigned char*)linetab) + (*linetab); linetab++;
191 	while(lx > 0) {
192 	  register int count = *data++;
193 	  if(count == 0xFF) break;
194 	  lx -= count;
195 	  if(lx <= 0) break;
196 	  count = *data++;
197 	  if(!count) continue;
198 	  if((lx - count) >= screenwidth) { lx -= count; data += count; continue; }
199 	  if(lx > screenwidth) { int diff = (lx - screenwidth); count -= diff; data += diff; lx = screenwidth; }
200 	  if((lx - count) < 0) { count = lx; }
201 	  for(; count > 0; count--) { --lx; dest[lx] = blend[((((int)(*data++))&0xFF)<<8)|dest[lx]]; }
202 	}
203   }
204 }
205 
206 /////////////////////////////////////////////////////////////////////////////
207 
putsprite_8(int x,int y,int is_flip,s_sprite * sprite,s_screen * screen,unsigned char * remap,unsigned char * blend)208 void putsprite_8(
209   int x, int y, int is_flip, s_sprite *sprite, s_screen *screen,
210   unsigned char *remap, unsigned char *blend
211 ) {
212   int *linetab;
213   int w, h;
214   unsigned char *dest;
215   // Get screen size
216   int screenwidth = screen->width;
217   int screenheight = screen->height;
218   // Adjust coords for centering
219   if(is_flip) x += sprite->centerx;
220   else x -= sprite->centerx;
221   y -= sprite->centery;
222   // Get sprite dimensions
223   w = sprite->width;
224   h = sprite->height;
225   // trivial clip all directions
226   if(is_flip)
227   {
228 	  if(x-w >= screenwidth) return;
229 	  if(x <= 0) return;
230   }
231   else
232   {
233 	  if(x >= screenwidth) return;
234 	  if((x+w) <= 0) return;
235   }
236   if(y >= screenheight) return;
237   if((y+h) <= 0) return;
238   // Init line table pointer
239   linetab = (int*)(sprite->data);
240   // clip top
241   if(y < 0) {
242 	h += y; // subtract from height
243 	linetab -= y; // add to linetab
244 	y = 0; // add to y
245   }
246   // clip bottom
247   if((y+h) > screenheight) {
248 	h = screenheight - y;
249   }
250   // calculate destination pointer
251   dest = ((unsigned char*)(screen->data)) + y*screenwidth;
252 
253   if(blend&&remap){
254 	if(is_flip) putsprite_remapblend_flip_(dest, x, linetab, h, screenwidth, remap, blend);
255 	else        putsprite_remapblend_     (dest, x  , linetab, h, screenwidth,remap, blend);
256   } else if(blend) {
257 	if(is_flip) putsprite_blend_flip_(dest, x, linetab, h, screenwidth, blend);
258 	else        putsprite_blend_     (dest, x  , linetab, h, screenwidth, blend);
259   } else if(remap) {
260 	if(is_flip) putsprite_remap_flip_(dest, x, linetab, h, screenwidth, remap);
261 	else        putsprite_remap_     (dest, x  , linetab, h, screenwidth, remap);
262   } else {
263 	if(is_flip) putsprite_flip_      (dest, x, linetab, h, screenwidth);
264 	else        putsprite_           (dest, x  , linetab, h, screenwidth);
265   }
266 }
267 
268 /////////////////////////////////////////////////////////////////////////////
269 
270 // scalex scaley flipy ...
putsprite_ex(int x,int y,s_sprite * frame,s_screen * screen,s_drawmethod * drawmethod)271 void putsprite_ex(int x, int y, s_sprite *frame, s_screen *screen, s_drawmethod* drawmethod)
272 {
273 	gfx_entry gfx;
274 
275 	if(!drawmethod->scalex || !drawmethod->scaley) return; // zero size
276 
277 	// no scale, no shift, no flip, no fill, so use common method
278 	if(drawmethod->scalex==256 && drawmethod->scaley==256 && !drawmethod->flipy && !drawmethod->shiftx && drawmethod->fillcolor==TRANSPARENT_IDX && !drawmethod->rotate && !drawmethod->centerx && !drawmethod->centery)
279 	{
280 		switch(screen->pixelformat)
281 		{
282 		case PIXEL_8:
283 			putsprite_8(x, y, drawmethod->flipx, frame, screen, drawmethod->table, drawmethod->alpha>0?blendtables[drawmethod->alpha-1]:NULL);
284 			break;
285 		case PIXEL_16:
286 			putsprite_x8p16(x, y, drawmethod->flipx, frame, screen, (unsigned short*)drawmethod->table, drawmethod->alpha>0?blendfunctions16[drawmethod->alpha-1]:NULL);
287 			break;
288 		case PIXEL_32:
289 			putsprite_x8p32(x, y, drawmethod->flipx, frame, screen, (unsigned*)drawmethod->table, drawmethod->alpha>0?blendfunctions32[drawmethod->alpha-1]:NULL);
290 			break;
291 		}
292 		return;
293 	}
294 
295 	gfx.type = gfx_sprite;
296 	gfx.sprite = frame;
297 
298 	if(drawmethod->water.watermode==3){
299 		gfx_draw_plane(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
300 	}else if(drawmethod->water.watermode){
301 		gfx_draw_water(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
302 	}else if(drawmethod->rotate){
303 		gfx_draw_rotate(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
304 	}else{
305 		gfx_draw_scale(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
306 	}
307 }
308 
putsprite(int x,int y,s_sprite * sprite,s_screen * screen,s_drawmethod * drawmethod)309 void putsprite(int x, int y, s_sprite* sprite, s_screen* screen, s_drawmethod* drawmethod)
310 {
311 	if(!drawmethod || drawmethod->flag==0)
312 	{
313 			goto plainsprite;
314 	}
315 
316 	putsprite_ex(x, y, sprite, screen, drawmethod);
317 	return;
318 plainsprite:
319 	switch(screen->pixelformat)
320 	{
321 	case PIXEL_8:
322 			putsprite_8(x, y, 0, sprite, screen, NULL, NULL);
323 			break;
324 	case PIXEL_16:
325 			putsprite_x8p16(x, y, 0, sprite, screen, (unsigned short*)sprite->palette, NULL);
326 			break;
327 	case PIXEL_32:
328 			putsprite_x8p32(x, y, 0, sprite, screen, (unsigned*)sprite->palette, NULL);
329 			break;
330 	}
331 }
332 
333 
334 
335 /////////////////////////////////////////////////////////////////////////////
336 //
337 // NULL for dest means do not actually encode
338 //
encodesprite(int centerx,int centery,s_bitmap * bitmap,s_sprite * dest)339 unsigned encodesprite(
340   int centerx, int centery,
341   s_bitmap *bitmap, s_sprite *dest
342 ) {
343   int x, x0, y, w, h;
344   unsigned char *data;
345   int *linetab;
346   unsigned char *src = bitmap->data;
347   int pb = PAL_BYTES, extrab;
348 
349   if(bitmap->width <= 0 || bitmap->height <= 0){
350 	// Image is empty (or bad), create an empty sprite
351 	if(dest) {
352 	  //dest->is_flip_of = NULL;
353 	  dest->centerx = 0;
354 	  dest->centery = 0;
355 	  dest->width = 0;
356 	  dest->height = 0;
357 	  dest->pixelformat = bitmap->pixelformat;
358 	  dest->mask = NULL;
359 	  dest->palette = NULL;
360 	}
361 	return sizeof(s_sprite);
362   }
363 
364   w = bitmap->width;
365   h = bitmap->height;
366 
367   if(dest) {
368 	//dest->is_flip_of = NULL;
369 	dest->centerx = centerx;
370 	dest->centery = centery;
371 	dest->width = w;
372 	dest->height = h;
373 	dest->pixelformat = bitmap->pixelformat;
374 	dest->mask = NULL;
375   }
376   linetab = (int*)(dest->data);
377   data = (unsigned char*)(linetab+h);
378 
379   for(y = 0; y < h; y++, src += w) {
380 	if(dest) { linetab[y] = ((size_t)data)-((size_t)(linetab+y)); }
381 	x = 0;
382 	for(;;) {
383 	  // search for the first visible pixel
384 	  x0 = x;
385 	  for(; (x < w) && ((x-x0)<0xFE); x++) { if(src[x]) break; }
386 	  // handle EOL
387 	  if(x >= w) { if(dest) { *data = 0xFF; } data++; break; }
388 	  // encode clearcount
389 	  if(dest) { *data = x-x0; } data++;
390 	  // if we're still not visible, encode a null visible count and continue
391 	  if(!src[x]) { if(dest) { *data = 0; } data++; continue; }
392 	  // search for the first invisible pixel
393 	  x0 = x;
394 	  for(; (x < w) && ((x-x0)<0xFF); x++) { if(!src[x]) break; }
395 	  // encode viscount and visible pixels
396 	  if(dest) {
397 		*data++ = x-x0;
398 		memcpy(data, src+x0, x-x0);
399 		data += x-x0;
400 	  } else {
401 		data += 1+(x-x0);
402 	  }
403 	}
404   }
405 
406   if(!bitmap->palette) pb = extrab = 0;
407   else
408   {
409 	 extrab = ((size_t)data)-((size_t)dest);
410 	 extrab %=4;
411 	 extrab = 4 - extrab;
412 	 extrab %=4;
413   }
414 
415   //point palette to the last byte of the pixel data
416   if(dest)
417   {
418 	  if(bitmap->palette) // if the bitmap contains palette, copy it
419 	  {
420 		  dest->palette = ((unsigned char*)data) + extrab ;
421 		  memcpy(dest->palette, bitmap->palette, pb);
422 	  }
423 	  else dest->palette = NULL;
424   }
425   return ((size_t)data)-((size_t)dest)+ extrab + pb+ANYNUMBER;
426 }
427 
428 /////////////////////////////////////////////////////////////////////////////
429 
fakey_encodesprite(s_bitmap * bitmap)430 unsigned fakey_encodesprite(s_bitmap *bitmap) {
431   return encodesprite(0, 0, bitmap, NULL);
432 }
433 
434 /////////////////////////////////////////////////////////////////////////////
435 
436