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 /////////////////////////////////////////////////////////////////////////////
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 xmin,int xmax,int * linetab,int h,int screenwidth)19 static void putsprite_(
20 unsigned char *dest, int x, int xmin, int xmax, int *linetab, 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 memcpy(dest + lx, data, count);
63 data += count;
64 lx += count;
65 }
66 }
67 }
68
putsprite_flip_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth)69 static void putsprite_flip_(
70 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth
71 )
72 {
73 for(; h > 0; h--, dest += screenwidth)
74 {
75 register int lx = x;
76 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
77 linetab++;
78 while(lx > xmin)
79 {
80 register int count = *data++;
81 if(count == 0xFF)
82 {
83 break;
84 }
85 lx -= count;
86 if(lx <= xmin)
87 {
88 break;
89 }
90 count = *data++;
91 if(!count)
92 {
93 continue;
94 }
95 if((lx - count) >= xmax)
96 {
97 lx -= count;
98 data += count;
99 continue;
100 }
101 if(lx > xmax)
102 {
103 int diff = (lx - xmax);
104 count -= diff;
105 data += diff;
106 lx = xmax;
107 }
108 if((lx - count) < xmin)
109 {
110 count = lx - xmin;
111 }
112 for(; count > 0; count--)
113 {
114 dest[--lx] = *data++;
115 }
116 //lx--;
117 //u8revcpy(dest+lx, data, count);
118 //lx-=count-1;
119 //data+=count;
120 }
121 }
122 }
123
putsprite_remap_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * remap)124 static void putsprite_remap_(
125 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
126 unsigned char *remap
127 )
128 {
129 for(; h > 0; h--, dest += screenwidth)
130 {
131 register int lx = x;
132 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
133 linetab++;
134 while(lx < xmax)
135 {
136 register int count = *data++;
137 if(count == 0xFF)
138 {
139 break;
140 }
141 lx += count;
142 if(lx >= xmax)
143 {
144 break;
145 }
146 count = *data++;
147 if(!count)
148 {
149 continue;
150 }
151 if((lx + count) <= xmin)
152 {
153 lx += count;
154 data += count;
155 continue;
156 }
157 if(lx < xmin)
158 {
159 int diff = lx - xmin;
160 count += diff;
161 data -= diff;
162 lx = xmin;
163 }
164 if((lx + count) > xmax)
165 {
166 count = xmax - lx;
167 }
168 for(; count > 0; count--)
169 {
170 dest[lx++] = remap[((int)(*data++)) & 0xFF];
171 }
172 //u8pcpy(dest+lx, data, remap, count);
173 //lx+=count;
174 //data+=count;
175 }
176 }
177 }
178
putsprite_remap_flip_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * remap)179 static void putsprite_remap_flip_(
180 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
181 unsigned char *remap
182 )
183 {
184 for(; h > 0; h--, dest += screenwidth)
185 {
186 register int lx = x;
187 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
188 linetab++;
189 while(lx > xmin)
190 {
191 register int count = *data++;
192 if(count == 0xFF)
193 {
194 break;
195 }
196 lx -= count;
197 if(lx <= xmin)
198 {
199 break;
200 }
201 count = *data++;
202 if(!count)
203 {
204 continue;
205 }
206 if((lx - count) >= xmax)
207 {
208 lx -= count;
209 data += count;
210 continue;
211 }
212 if(lx > xmax)
213 {
214 int diff = (lx - xmax);
215 count -= diff;
216 data += diff;
217 lx = xmax;
218 }
219 if((lx - count) < xmin)
220 {
221 count = lx - xmin;
222 }
223 for(; count > 0; count--)
224 {
225 dest[--lx] = remap[((int)(*data++)) & 0xFF];
226 }
227 //lx--;
228 //u8revpcpy(dest+lx, data, remap, count);
229 //lx-=count-1;
230 //data+=count;
231 }
232 }
233 }
234
235 //src high dest low
putsprite_remapblend_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)236 static void putsprite_remapblend_(
237 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
238 unsigned char *remap, unsigned char *blend
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 while(lx < xmax)
247 {
248 register int count = *data++;
249 if(count == 0xFF)
250 {
251 break;
252 }
253 lx += count;
254 if(lx >= xmax)
255 {
256 break;
257 }
258 count = *data++;
259 if(!count)
260 {
261 continue;
262 }
263 if((lx + count) <= xmin)
264 {
265 lx += count;
266 data += count;
267 continue;
268 }
269 if(lx < xmin)
270 {
271 int diff = lx - xmin;
272 count += diff;
273 data -= diff;
274 lx = xmin;
275 }
276 if((lx + count) > xmax)
277 {
278 count = xmax - lx;
279 }
280 for(; count > 0; count--)
281 {
282 dest[lx] = blend[(remap[(((int)(*data++)) & 0xFF)] << 8) | dest[lx]];
283 lx++;
284 }
285 }
286 }
287 }
288
putsprite_remapblend_flip_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * remap,unsigned char * blend)289 static void putsprite_remapblend_flip_(
290 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
291 unsigned char *remap, unsigned char *blend
292 )
293 {
294 for(; h > 0; h--, dest += screenwidth)
295 {
296 register int lx = x;
297 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
298 linetab++;
299 while(lx > xmin)
300 {
301 register int count = *data++;
302 if(count == 0xFF)
303 {
304 break;
305 }
306 lx -= count;
307 if(lx <= xmin)
308 {
309 break;
310 }
311 count = *data++;
312 if(!count)
313 {
314 continue;
315 }
316 if((lx - count) >= xmax)
317 {
318 lx -= count;
319 data += count;
320 continue;
321 }
322 if(lx > xmax)
323 {
324 int diff = (lx - xmax);
325 count -= diff;
326 data += diff;
327 lx = xmax;
328 }
329 if((lx - count) < xmin)
330 {
331 count = lx - xmin;
332 }
333 for(; count > 0; count--)
334 {
335 --lx;
336 dest[lx] = blend[(remap[(((int)(*data++)) & 0xFF)] << 8) | dest[lx]];
337 }
338 }
339 }
340 }
341
putsprite_blend_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * blend)342 static void putsprite_blend_(
343 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
344 unsigned char *blend
345 )
346 {
347 for(; h > 0; h--, dest += screenwidth)
348 {
349 register int lx = x;
350 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
351 linetab++;
352 while(lx < xmax)
353 {
354 register int count = *data++;
355 if(count == 0xFF)
356 {
357 break;
358 }
359 lx += count;
360 if(lx >= xmax)
361 {
362 break;
363 }
364 count = *data++;
365 if(!count)
366 {
367 continue;
368 }
369 if((lx + count) <= xmin)
370 {
371 lx += count;
372 data += count;
373 continue;
374 }
375 if(lx < xmin)
376 {
377 int diff = lx - xmin;
378 count += diff;
379 data -= diff;
380 lx = xmin;
381 }
382 if((lx + count) > xmax)
383 {
384 count = xmax - lx;
385 }
386 for(; count > 0; count--)
387 {
388 dest[lx] = blend[((((int)(*data++)) & 0xFF) << 8) | dest[lx]];
389 lx++;
390 }
391 }
392 }
393 }
394
putsprite_blend_flip_(unsigned char * dest,int x,int xmin,int xmax,int * linetab,int h,int screenwidth,unsigned char * blend)395 static void putsprite_blend_flip_(
396 unsigned char *dest, int x, int xmin, int xmax, int *linetab, int h, int screenwidth,
397 unsigned char *blend
398 )
399 {
400 for(; h > 0; h--, dest += screenwidth)
401 {
402 register int lx = x;
403 unsigned char *data = ((unsigned char *)linetab) + (*linetab);
404 linetab++;
405 while(lx > xmin)
406 {
407 register int count = *data++;
408 if(count == 0xFF)
409 {
410 break;
411 }
412 lx -= count;
413 if(lx <= xmin)
414 {
415 break;
416 }
417 count = *data++;
418 if(!count)
419 {
420 continue;
421 }
422 if((lx - count) >= xmax)
423 {
424 lx -= count;
425 data += count;
426 continue;
427 }
428 if(lx > xmax)
429 {
430 int diff = (lx - screenwidth);
431 count -= diff;
432 data += diff;
433 lx = screenwidth;
434 }
435 if((lx - count) < xmin)
436 {
437 count = lx - xmin;
438 }
439 for(; count > 0; count--)
440 {
441 --lx;
442 dest[lx] = blend[((((int)(*data++)) & 0xFF) << 8) | dest[lx]];
443 }
444 }
445 }
446 }
447
448 /////////////////////////////////////////////////////////////////////////////
449
putsprite_8(int x,int y,int is_flip,s_sprite * sprite,s_screen * screen,unsigned char * remap,unsigned char * blend)450 void putsprite_8(
451 int x, int y, int is_flip, s_sprite *sprite, s_screen *screen,
452 unsigned char *remap, unsigned char *blend
453 )
454 {
455 int *linetab;
456 int w, h;
457 unsigned char *dest;
458 // Get screen size
459 int screenwidth = screen->width;
460 int xmin = useclip ? MAX(clipx1, 0) : 0,
461 xmax = useclip ? MIN(clipx2, screen->width) : screen->width,
462 ymin = useclip ? MAX(clipy1, 0) : 0,
463 ymax = useclip ? MIN(clipy2, screen->height) : screen->height;
464 // Adjust coords for centering
465 if(is_flip)
466 {
467 x += sprite->centerx;
468 }
469 else
470 {
471 x -= sprite->centerx;
472 }
473 y -= sprite->centery;
474 // Get sprite dimensions
475 w = sprite->width;
476 h = sprite->height;
477 // trivial clip all directions
478 if(is_flip)
479 {
480 if(x - w >= xmax)
481 {
482 return;
483 }
484 if(x <= xmin)
485 {
486 return;
487 }
488 }
489 else
490 {
491 if(x >= xmax)
492 {
493 return;
494 }
495 if((x + w) <= xmin)
496 {
497 return;
498 }
499 }
500 if(y >= ymax)
501 {
502 return;
503 }
504 if((y + h) <= ymin)
505 {
506 return;
507 }
508 // Init line table pointer
509 linetab = (int *)(sprite->data);
510 // clip top
511 if(y < ymin)
512 {
513 h += y - ymin; // subtract from height
514 linetab -= y - ymin; // add to linetab
515 y = ymin; // add to y
516 }
517 // clip bottom
518 if((y + h) > ymax)
519 {
520 h = ymax - y;
521 }
522 // calculate destination pointer
523 dest = ((unsigned char *)(screen->data)) + y * screenwidth;
524
525 if(blend && remap)
526 {
527 if(is_flip)
528 {
529 putsprite_remapblend_flip_(dest, x, xmin, xmax, linetab, h, screenwidth, remap, blend);
530 }
531 else
532 {
533 putsprite_remapblend_ (dest, x, xmin, xmax , linetab, h, screenwidth, remap, blend);
534 }
535 }
536 else if(blend)
537 {
538 if(is_flip)
539 {
540 putsprite_blend_flip_(dest, x, xmin, xmax, linetab, h, screenwidth, blend);
541 }
542 else
543 {
544 putsprite_blend_ (dest, x, xmin, xmax , linetab, h, screenwidth, blend);
545 }
546 }
547 else if(remap)
548 {
549 if(is_flip)
550 {
551 putsprite_remap_flip_(dest, x, xmin, xmax, linetab, h, screenwidth, remap);
552 }
553 else
554 {
555 putsprite_remap_ (dest, x, xmin, xmax , linetab, h, screenwidth, remap);
556 }
557 }
558 else
559 {
560 if(is_flip)
561 {
562 putsprite_flip_ (dest, x, xmin, xmax, linetab, h, screenwidth);
563 }
564 else
565 {
566 putsprite_ (dest, x, xmin, xmax , linetab, h, screenwidth);
567 }
568 }
569 }
570
571 /////////////////////////////////////////////////////////////////////////////
572
573 // scalex scaley flipy ...
putsprite_ex(int x,int y,s_sprite * frame,s_screen * screen,s_drawmethod * drawmethod)574 void putsprite_ex(int x, int y, s_sprite *frame, s_screen *screen, s_drawmethod *drawmethod)
575 {
576 gfx_entry gfx;
577
578 if(!drawmethod->scalex || !drawmethod->scaley)
579 {
580 return; // zero size
581 }
582
583 // no scale, no shift, no flip, no fill, so use common method
584 if(!drawmethod->water.watermode && drawmethod->scalex == 256 && drawmethod->scaley == 256 && !drawmethod->flipy && !drawmethod->shiftx && drawmethod->fillcolor == TRANSPARENT_IDX && !drawmethod->rotate)
585 {
586 if(drawmethod->flipx)
587 {
588 x += drawmethod->centerx;
589 }
590 else
591 {
592 x -= drawmethod->centerx;
593 }
594 y -= drawmethod->centery;
595 switch(screen->pixelformat)
596 {
597 case PIXEL_8:
598 putsprite_8(x, y, drawmethod->flipx, frame, screen, drawmethod->table, drawmethod->alpha > 0 ? blendtables[drawmethod->alpha - 1] : NULL);
599 break;
600 case PIXEL_16:
601 putsprite_x8p16(x, y, drawmethod->flipx, frame, screen, (unsigned short *)drawmethod->table, getblendfunction16(drawmethod->alpha));
602 break;
603 case PIXEL_32:
604 putsprite_x8p32(x, y, drawmethod->flipx, frame, screen, (unsigned *)drawmethod->table, getblendfunction32(drawmethod->alpha));
605 break;
606 }
607 return;
608 }
609
610 gfx.sprite = frame;
611
612 if(drawmethod->water.watermode == 3 && drawmethod->water.beginsize > 0)
613 {
614 gfx_draw_plane(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
615 }
616 else if(drawmethod->water.watermode && drawmethod->water.amplitude)
617 {
618 gfx_draw_water(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
619 }
620 else if(drawmethod->rotate)
621 {
622 gfx_draw_rotate(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
623 }
624 else
625 {
626 gfx_draw_scale(screen, &gfx, x, y, frame->centerx, frame->centery, drawmethod);
627 }
628 }
629
_putsprite(int x,int y,s_sprite * sprite,s_screen * screen,s_drawmethod * drawmethod)630 static void _putsprite(int x, int y, s_sprite *sprite, s_screen *screen, s_drawmethod *drawmethod)
631 {
632 if(!drawmethod || drawmethod->flag == 0)
633 {
634 goto plainsprite;
635 }
636
637 putsprite_ex(x, y, sprite, screen, drawmethod);
638 return;
639 plainsprite:
640 switch(screen->pixelformat)
641 {
642 case PIXEL_8:
643 putsprite_8(x, y, 0, sprite, screen, NULL, NULL);
644 break;
645 case PIXEL_16:
646 putsprite_x8p16(x, y, 0, sprite, screen, (unsigned short *)sprite->palette, NULL);
647 break;
648 case PIXEL_32:
649 putsprite_x8p32(x, y, 0, sprite, screen, (unsigned *)sprite->palette, NULL);
650 break;
651 }
652 }
653
putsprite(int x,int y,s_sprite * sprite,s_screen * screen,s_drawmethod * drawmethod)654 void putsprite(int x, int y, s_sprite *sprite, s_screen *screen, s_drawmethod *drawmethod)
655 {
656 int xrepeat, yrepeat, xspan, yspan, i, j, dx, dy;
657
658 drawmethod_global_init(drawmethod);
659
660 if(drawmethod && drawmethod->flag)
661 {
662 xrepeat = drawmethod->xrepeat;
663 yrepeat = drawmethod->yrepeat;
664 xspan = drawmethod->xspan;
665 yspan = drawmethod->yspan;
666 }
667 else
668 {
669 xrepeat = yrepeat = 1;
670 xspan = yspan = 0;
671 }
672
673 for(j = 0, dy = y; j < yrepeat; j++, dy += yspan)
674 {
675 for(i = 0, dx = x; i < xrepeat; i++, dx += xspan)
676 {
677 _putsprite(dx, dy, sprite, screen, drawmethod);
678 }
679 }
680
681 }
682
683
684
685 /////////////////////////////////////////////////////////////////////////////
686 //
687 // NULL for dest means do not actually encode
688 //
encodesprite(int centerx,int centery,s_bitmap * bitmap,s_sprite * dest)689 unsigned encodesprite(
690 int centerx, int centery,
691 s_bitmap *bitmap, s_sprite *dest
692 )
693 {
694 int x, x0, y, w, h, xoffset, origwidth;
695 unsigned char *data;
696 int *linetab;
697 unsigned char *src = bitmap->data;
698 int pb = PAL_BYTES, extrab;
699
700 if(dest)
701 {
702 dest->magic = sprite_magic;
703 }
704
705 if(bitmap->clipped_width <= 0 || bitmap->clipped_height <= 0)
706 {
707 // Image is empty (or bad), create an empty sprite
708 if(dest)
709 {
710 //dest->is_flip_of = NULL;
711 dest->centerx = 0;
712 dest->centery = 0;
713 dest->width = 0;
714 dest->height = 0;
715 dest->pixelformat = bitmap->pixelformat;
716 dest->mask = NULL;
717 dest->palette = NULL;
718 }
719 return sizeof(s_sprite);
720 }
721
722 w = bitmap->clipped_width;
723 h = bitmap->clipped_height;
724 xoffset = bitmap->clipped_x_offset;
725 origwidth = bitmap->width;
726
727 if(dest)
728 {
729 //dest->is_flip_of = NULL;
730 dest->centerx = centerx;
731 dest->centery = centery;
732 dest->width = w;
733 dest->height = h;
734 dest->pixelformat = bitmap->pixelformat;
735 dest->mask = NULL;
736 }
737 linetab = (int *)(dest->data);
738 data = (unsigned char *)(linetab + h);
739
740 src += bitmap->clipped_y_offset * origwidth;
741 src += xoffset;
742
743 for(y = 0; y < h; y++, src += origwidth)
744 {
745 if(dest)
746 {
747 linetab[y] = ((size_t)data) - ((size_t)(linetab + y));
748 }
749 x = 0;
750 for(;;)
751 {
752 // search for the first visible pixel
753 x0 = x;
754 for(; (x < w) && ((x - x0) < 0xFE); x++)
755 {
756 if(src[x])
757 {
758 break;
759 }
760 }
761 // handle EOL
762 if(x >= w)
763 {
764 if(dest)
765 {
766 *data = 0xFF;
767 }
768 data++;
769 break;
770 }
771 // encode clearcount
772 if(dest)
773 {
774 *data = x - x0;
775 }
776 data++;
777 // if we're still not visible, encode a null visible count and continue
778 if(!src[x])
779 {
780 if(dest)
781 {
782 *data = 0;
783 }
784 data++;
785 continue;
786 }
787 // search for the first invisible pixel
788 x0 = x;
789 for(; (x < w) && ((x - x0) < 0xFF); x++)
790 {
791 if(!src[x])
792 {
793 break;
794 }
795 }
796 // encode viscount and visible pixels
797 if(dest)
798 {
799 *data++ = x - x0;
800 memcpy(data, src + x0, x - x0);
801 data += x - x0;
802 }
803 else
804 {
805 data += 1 + (x - x0);
806 }
807 }
808 }
809
810 if(!bitmap->palette)
811 {
812 pb = extrab = 0;
813 }
814 else
815 {
816 extrab = ((size_t)data) - ((size_t)dest);
817 extrab %= 4;
818 extrab = 4 - extrab;
819 extrab %= 4;
820 }
821
822 //point palette to the last byte of the pixel data
823 if(dest)
824 {
825 if(bitmap->palette) // if the bitmap contains palette, copy it
826 {
827 dest->palette = ((unsigned char *)data) + extrab ;
828 memcpy(dest->palette, bitmap->palette, pb);
829 }
830 else
831 {
832 dest->palette = NULL;
833 }
834 }
835 return ((size_t)data) - ((size_t)dest) + extrab + pb + ANYNUMBER;
836 }
837
838 /////////////////////////////////////////////////////////////////////////////
839
fakey_encodesprite(s_bitmap * bitmap)840 unsigned fakey_encodesprite(s_bitmap *bitmap)
841 {
842 return encodesprite(0, 0, bitmap, NULL);
843 }
844
845 /////////////////////////////////////////////////////////////////////////////
846
847