1 /*
2 New sprite code, should work in all resolutions.
3
4 To do:
5 - Rewrite optimized code in ASM.
6
7
8 Format description:
9
10 Offs Size Description
11 --------------------------------------------
12 0 4 Center x coordinate
13 4 4 Center y coordinate
14 8 4 Image width
15 12 4 Image height
16 16 height*4 Line offset table (see below)
17 ? ? RLE-encoded image data (see below)
18
19
20 Format of the line offset table:
21
22 Every DWORD in the line offset table points to the start of the
23 corresponding line as follows:
24
25 lineptr = tableptr + *tableptr;
26
27
28 Format of the RLE-encoded image data:
29
30 * The data is encoded per line.
31 * The data is DWORD-aligned.
32 * When decoding a line, the destination pointer will be reset
33 to it's original position when the end of the line is reached.
34 The data must be formatted properly for this.
35
36
37 RLE data block format:
38 DWORD advance pointer "clearcount"
39 DWORD pixel count "viscount"
40 (4*?) BYTES pixels
41
42 The final clearcount in a line will have a zero or negative value.
43 This value is used to reset the destination pointer to the start
44 of the line. The decoding algorithm then adds the screenwidth to
45 this pointer, to advance to the next line.
46
47 The final viscount will have a zero value, serving as an
48 end-of-line indicator.
49
50 There is no end-of-sprite indicator; the decoding algorithm
51 simply uses a height counter.
52
53 Invalid sprite dimensions (<=0) are checked by the decoding
54 algorithm.
55 */
56
57
58 #include "types.h"
59 #include "sprite.h"
60
61
62
63 static int screenwidth = 16;
64 static int screenheight = 16;
65
66
67 /*
68 Left AND right clipping, seems OK.
69
70 This code continues where the other code cannot.
71
72 PRE:
73 - X and Y coords have been adjusted for sprite centering.
74 - Vertical clipping adjustments have been performed, if necessary.
75 - The frame pointer points at the line offset table of the sprite.
76 */
ps_bothclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c)77 static void ps_bothclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c){
78
79 int viscount, viscount_dwords, viscount_bytes;
80 unsigned long pixelblock;
81 unsigned long *data = linetab;
82 int clipcount;
83 unsigned char * charptr;
84 int widthcount;
85 unsigned char *dest_old;
86
87
88 // I know the x coord is negative! But this is OK anyway.
89 dest_c += y*screenwidth + x;
90
91 do{
92 // Get ready to draw a line
93 data = linetab + (*linetab / 4);
94 ++linetab;
95
96 dest_old = dest_c;
97 widthcount = screenwidth;
98
99 // The following for-loop contains code to skip the left offscreen
100 // area of the sprite. Complex shit, especially since it also has
101 // to clip on the right side now!
102
103 clipcount = x;
104 for(;;){
105
106 clipcount += *data; // Add clearcount
107 ++data;
108 if(clipcount >= 0){
109 // Reached on-screen area?
110 // Check if we've passed the screen entirely!
111 if(clipcount >= screenwidth) goto bclip_nextline_entry;
112
113 // Move the screen pointer to the left-most pixel on-screen.
114 dest_c -= x;
115 // Now add the clipcount overflow.
116 dest_c += clipcount;
117
118 // Keep the width counter in check.
119 widthcount -= clipcount;
120
121 goto bclip_entry1;
122 }
123
124
125 viscount = *data; // Get viscount
126 ++data;
127
128
129 if(viscount <= 0) goto bclip_nextline_entry; // Reached EOL?
130
131
132 if((viscount + clipcount) <= 0){
133 // These pixels can be safely skipped.
134 clipcount += viscount;
135
136 // Skip the pixels.
137 viscount += 3;
138 data += viscount>>2;
139
140 continue;
141 }
142
143
144 // The pixel run crosses the screen boundary!
145
146 charptr = (void*)data;
147
148 // Locate aligned position for frame pointer, past the pixels.
149 data += (viscount+3) >> 2;
150
151 // Move the screen pointer to the left-most pixel on-screen.
152 dest_c -= x;
153
154
155 charptr -= clipcount; // Find pixels to draw
156 viscount += clipcount; // How many pixels left to draw?
157
158 if(viscount >= screenwidth){
159 // Fill entire width of screen (dest-aligned).
160 // In ASM, this will copy DWORDs.
161 viscount = screenwidth;
162 do{
163 *dest_c = *charptr;
164 ++dest_c;
165 ++charptr;
166 }while(--viscount);
167 goto bclip_nextline_entry;
168 }
169
170 // Keep the width counter updated.
171 widthcount -= viscount;
172
173 // Draw this run's remaining pixels to the screen.
174 // Dest-aligned, will copy DWORDs in ASM.
175 do{
176 *dest_c = *charptr;
177 ++dest_c;
178 ++charptr;
179 }while(--viscount);
180
181 break; // Continue with right-clipped draw loop.
182 }
183
184
185 for(;;){
186 dest_c += *data; // Add clearcount
187 widthcount -= *data;
188 if(widthcount<=0) break; // Clip and go do the next line
189 ++data;
190
191 bclip_entry1:
192
193 viscount = *data;
194 ++data;
195
196
197 if(viscount<=0) break; // EOL
198
199
200 // If too many pixels to draw, cap run.
201 widthcount -= viscount;
202 if(widthcount<0) viscount += widthcount;
203
204
205 viscount_dwords = viscount >> 2;
206 viscount_bytes = viscount & 3;
207
208 #if 0
209 // Move DWORDS
210 if ((int)dest_c & 3) {
211 while(viscount_dwords){
212 pixelblock = *data++;
213 dest_c[0] = pixelblock;
214 pixelblock >>= 8;
215 dest_c[1] = pixelblock;
216 pixelblock >>= 8;
217 dest_c[2] = pixelblock;
218 pixelblock >>= 8;
219 dest_c[3] = pixelblock;
220 dest_c += 4;
221 --viscount_dwords;
222 }
223 } else
224 #endif
225 {
226 while(viscount_dwords){
227 *(unsigned long*)dest_c = *data++;
228 dest_c += 4;
229 --viscount_dwords;
230 }
231 }
232
233 // Move (max. 3) single bytes?
234 if((--viscount_bytes)<0) goto bclip_finalcheck;
235 pixelblock = *data++;
236
237 *dest_c++ = pixelblock;
238
239 if((--viscount_bytes)<0) goto bclip_finalcheck;
240 pixelblock >>= 8;
241 *dest_c++ = pixelblock;
242
243 if((--viscount_bytes)<0) goto bclip_finalcheck;
244 pixelblock >>= 8;
245 *dest_c++ = pixelblock;
246
247 bclip_finalcheck:
248 if(widthcount<=0) break; // Clip and go do the next line
249 };
250
251
252 bclip_nextline_entry:
253
254 dest_c = dest_old + screenwidth;
255
256 }while(--height);
257 }
258
259
260
261
262
263 /*
264 Right-side clipping, seems OK.
265
266 This code continues where the unclipped putsprite code cannot.
267
268 PRE:
269 - X and Y coords have been adjusted for sprite centering.
270 - Vertical clipping adjustments have been performed, if necessary.
271 */
ps_rightclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c)272 static void ps_rightclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c){
273
274 int viscount, viscount_dwords, viscount_bytes;
275 unsigned long pixelblock;
276 unsigned long *data = linetab;
277 int widthcount;
278 unsigned char *dest_old;
279
280
281 // Still visible?
282 if(x >= screenwidth) return;
283
284
285 // No need to check left-side clipping, should be done by leftclip code!
286
287
288 // Get the screen pointer ready...
289 dest_c += y*screenwidth + x;
290
291
292 // Calculate the remaining width.
293 width = screenwidth - x;
294
295
296 do{
297 // Get ready to draw a line
298 data = linetab + (*linetab / 4);
299 ++linetab;
300
301 dest_old = dest_c;
302 widthcount = width;
303
304 for(;;){
305 dest_c += *data; // Add clearcount
306 widthcount -= *data;
307 if(widthcount<=0) break; // Clip and go do the next line
308 ++data;
309
310 viscount = *data;
311 ++data;
312
313
314 if(viscount<=0) break; // EOL
315
316
317 // If too many pixels to draw, cap run.
318 widthcount -= viscount;
319 if(widthcount<0) viscount += widthcount;
320
321
322 viscount_dwords = viscount >> 2;
323 viscount_bytes = viscount & 3;
324 #if 0
325 if ((int)dest_c & 3) {
326 while(viscount_dwords){
327 pixelblock = *data++;
328 dest_c[0] = pixelblock;
329 pixelblock >>= 8;
330 dest_c[1] = pixelblock;
331 pixelblock >>= 8;
332 dest_c[2] = pixelblock;
333 pixelblock >>= 8;
334 dest_c[3] = pixelblock;
335 dest_c += 4;
336 --viscount_dwords;
337 }
338 } else
339 #endif
340 {
341 while(viscount_dwords){
342 *(unsigned long*)dest_c = *data++;
343 dest_c += 4;
344 --viscount_dwords;
345 }
346 }
347
348 // Move (max. 3) single bytes?
349 if((--viscount_bytes)<0) goto rclip_finalcheck;
350 pixelblock = *data++;
351
352 *dest_c++ = pixelblock;
353
354 if((--viscount_bytes)<0) goto rclip_finalcheck;
355 pixelblock >>= 8;
356 *dest_c++ = pixelblock;
357
358 if((--viscount_bytes)<0) goto rclip_finalcheck;
359 pixelblock >>= 8;
360 *dest_c++ = pixelblock;
361
362 rclip_finalcheck:
363 if(widthcount<=0) break; // Clip and go do the next line
364 };
365
366 dest_c = dest_old + screenwidth;
367
368 }while(--height);
369 }
370
371
372
373
374 /*
375 Left clipping, seems OK.
376
377 This code continues where the unclipped putsprite code cannot.
378
379 PRE:
380 - X and Y coords have been adjusted for sprite centering.
381 - Vertical clipping adjustments have been performed, if necessary.
382 */
ps_leftclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c)383 static void ps_leftclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c){
384
385 int viscount, viscount_dwords, viscount_bytes;
386 unsigned long pixelblock;
387 unsigned long *data = linetab;
388 int clipcount;
389 unsigned char * charptr;
390
391
392 // Still visible?
393 if(-x >= width) return;
394
395
396 // Check right clipping
397 if(x+width > screenwidth){
398 ps_bothclip(x, y, width, height, data, dest_c);
399 return;
400 }
401
402
403 // I know the x coord is negative! But this is OK anyway.
404 dest_c += y*screenwidth + x;
405
406 do{
407 // Get ready to draw a line
408 data = linetab + (*linetab / 4);
409 ++linetab;
410
411
412 // The following for-loop contains code to skip the left offscreen
413 // area of the sprite. Complex shit!
414
415 clipcount = x;
416 for(;;){
417
418 clipcount += *data; // Add clearcount
419 ++data;
420 if(clipcount >= 0){
421 // Reached on-screen area!
422 // Move the screen pointer to the left-most pixel on-screen.
423 dest_c -= x;
424 // Now add the clipcount overflow.
425 dest_c += clipcount;
426 goto lclip_entry1;
427 }
428
429
430 viscount = *data; // Get viscount
431 ++data;
432
433
434 if(viscount <= 0) goto lclip_nextline_entry; // Reached EOL?
435
436
437 if((viscount + clipcount) <= 0){
438 // These pixels can be safely skipped.
439 clipcount += viscount;
440
441 // Skip the pixels.
442 viscount += 3;
443 data += viscount>>2;
444
445 continue;
446 }
447
448
449 // The pixel run crosses the screen boundary!
450
451 charptr = (void*)data;
452
453 // Locate aligned position for source data pointer, past the pixels.
454 data += (viscount+3) >> 2;
455
456 charptr -= clipcount; // Find pixels to draw
457 viscount += clipcount; // How many pixels left to draw?
458
459 // Move the screen pointer to the left-most pixel on-screen.
460 dest_c -= x;
461
462 // Draw this run's remaining pixels to the screen.
463 // Dest-aligned, will copy DWORDs in ASM.
464 do{
465 *dest_c = *charptr;
466 ++dest_c;
467 ++charptr;
468 }while(--viscount);
469
470 break; // Continue with normal draw loop.
471 }
472
473
474 // Normal draw loop...
475 for(;;){
476 dest_c += *data; // Add clearcount
477 ++data;
478
479 lclip_entry1:
480
481 viscount = *data;
482 ++data;
483
484 if(viscount<=0) break;
485
486 viscount_dwords = viscount >> 2;
487 viscount_bytes = viscount & 3;
488 #if 0
489 // Move DWORDS
490 if ((int)dest_c & 3) {
491 while(viscount_dwords){
492 pixelblock = *data++;
493 dest_c[0] = pixelblock;
494 pixelblock >>= 8;
495 dest_c[1] = pixelblock;
496 pixelblock >>= 8;
497 dest_c[2] = pixelblock;
498 pixelblock >>= 8;
499 dest_c[3] = pixelblock;
500 dest_c += 4;
501 --viscount_dwords;
502 }
503 } else
504 #endif
505 {
506 while(viscount_dwords){
507 *(unsigned long*)dest_c = *data++;
508 dest_c += 4;
509 --viscount_dwords;
510 }
511 }
512
513 // Move (max. 3) single bytes?
514 if((--viscount_bytes)<0) continue;
515 pixelblock = *data++;
516
517 *dest_c++ = pixelblock;
518
519 if((--viscount_bytes)<0) continue;
520 pixelblock >>= 8;
521 *dest_c++ = pixelblock;
522
523 if((--viscount_bytes)<0) continue;
524 pixelblock >>= 8;
525 *dest_c++ = pixelblock;
526 };
527
528 lclip_nextline_entry:
529
530 dest_c += screenwidth;
531
532 }while(--height);
533 }
534
535
536 // This seems OK...
putsprite(int x,int y,s_sprite * frame,s_screen * screen)537 void putsprite(int x, int y, s_sprite *frame, s_screen *screen){
538
539 unsigned long *linetab;
540 int width, height;
541 int viscount, viscount_dwords, viscount_bytes;
542 unsigned long pixelblock;
543 unsigned long *data;
544 unsigned char *dest_c;
545
546
547 // Get screen size
548 screenwidth = screen->width;
549 screenheight = screen->height;
550
551 dest_c = screen->data;
552
553
554 // Adjust coords for centering
555 x -= frame->centerx;
556 y -= frame->centery;
557
558
559 // Get sprite dimensions
560 width = frame->width;
561 height = frame->height;
562
563
564 // Check if sprite dimensions are valid
565 if(width<=0 || height<=0) return;
566
567
568 // Init line table pointer
569 linetab = (void*)frame->data;
570
571
572 // Check clipping, vertical first
573 if(y < 0){
574 // Clip top
575 height += y; // Make sprite shorter
576 if(height <=0 ) return;
577 linetab -= y; // Advance -y lines
578 y = 0;
579 }
580 if(y+height > screenheight){
581 // Clip bottom (make sprite shorter)
582 height = screenheight - y;
583 if(height <= 0) return;
584 }
585 if(x < 0){
586 // Clip left
587 ps_leftclip(x, y, width, height, linetab, dest_c);
588 return;
589 }
590 if(x+width > screenwidth){
591 // Clip right
592 ps_rightclip(x, y, width, height, linetab, dest_c);
593 return;
594 }
595
596
597 dest_c += y*screenwidth + x;
598
599
600 do{
601 // Get ready to draw a line
602 data = linetab + (*linetab / 4);
603 ++linetab;
604
605 for(;;){
606 dest_c += *data; // Add clearcount
607 ++data;
608
609 viscount = *data;
610 ++data;
611
612 if(viscount<=0) break;
613
614 viscount_dwords = viscount >> 2;
615 viscount_bytes = viscount & 3;
616
617 #if 0
618 if ((int)dest_c & 3) {
619 while(viscount_dwords) {
620 pixelblock = *data++;
621 dest_c[0] = pixelblock;
622 pixelblock >>= 8;
623 dest_c[1] = pixelblock;
624 pixelblock >>= 8;
625 dest_c[2] = pixelblock;
626 pixelblock >>= 8;
627 dest_c[3] = pixelblock;
628 dest_c += 4;
629 --viscount_dwords;
630 }
631 } else
632 #endif
633 {
634 // Move DWORDS
635 while(viscount_dwords){
636 *(unsigned long*)dest_c = *data++;
637 dest_c += 4;
638 --viscount_dwords;
639 }
640 }
641
642 // Move (max. 3) single bytes?
643 if((--viscount_bytes)<0) continue;
644 pixelblock = *data++;
645
646 *dest_c++ = pixelblock;
647
648 if((--viscount_bytes)<0) continue;
649 pixelblock >>= 8;
650 *dest_c++ = pixelblock;
651
652 if((--viscount_bytes)<0) continue;
653 pixelblock >>= 8;
654 *dest_c++ = pixelblock;
655 };
656
657 dest_c += screenwidth;
658
659 }while(--height);
660 }
661
662
663
664
665
666
667 // To know size of sprite without actually creating one
fakey_encodesprite(s_bitmap * bitmap)668 unsigned int fakey_encodesprite(s_bitmap *bitmap){
669 unsigned int width, height, s, d;
670 unsigned int vispix, xpos, ypos, pos;
671
672 if(bitmap->width <= 0 || bitmap->height <= 0){
673 // Image is empty (or bad), return size of empty sprite
674 return 8*4;
675 }
676
677 width = bitmap->width;
678 height = bitmap->height;
679
680 xpos=0;
681 ypos=0;
682
683 s = 0; // Source pixels start pos
684 d = 16+(height<<2); // Destination pixels start pos
685
686 ctn:
687 while(ypos<height){
688 while(bitmap->data[s]==TRANSPARENT_IDX){
689 ++s;
690 ++xpos;
691 if(xpos==width){
692 d += 8;
693 xpos = 0;
694 ++ypos;
695 goto ctn; // Re-enter loop
696 }
697 }
698
699 d+=4;
700
701 pos = s;
702 vispix = 0;
703
704 while(bitmap->data[pos]!=TRANSPARENT_IDX && xpos<width){
705 ++vispix;
706 ++xpos;
707 ++pos;
708 }
709 d+=4;
710
711 d += vispix;
712 s += vispix;
713
714 // Add alignment
715 while(d&3) d++;
716
717 if(xpos>=width){ // Stopped at end of line?
718 d += 8;
719 xpos = 0;
720 ++ypos;
721 }
722 }
723 return d; // Return size of encoded sprite
724 }
725
726
727
728
729 // Bitmap-to-sprite converter, now screensize-independent!
encodesprite(int centerx,int centery,s_bitmap * bitmap,s_sprite * dest)730 unsigned int encodesprite(int centerx, int centery, s_bitmap *bitmap, s_sprite *dest){
731
732 unsigned int width, height, s, d;
733 unsigned int vispix, transpix, xpos, ypos, pos;
734 unsigned char *cdest = (void*)dest->data;
735 long *linetab = (void*)dest->data;
736
737
738 if(bitmap->width <= 0 || bitmap->height <= 0){
739 // Image is empty (or bad), create an empty sprite
740 dest->centerx = 0;
741 dest->centery = 0;
742 dest->width = 0;
743 dest->height = 0;
744 for(d=0; d<4; d++) dest->data[d] = 0;
745 return 8*4;
746 }
747
748 width = bitmap->width;
749 height = bitmap->height;
750
751
752 dest->centerx = centerx;
753 dest->centery = centery;
754 dest->width = width;
755 dest->height = height;
756
757 xpos = 0;
758 ypos = 0;
759
760 s = 0; // Source pixels start pos
761 d = height<<2; // Destination pixels start pos
762
763 ctn:
764
765 while(ypos < height){
766
767 if(xpos==0){
768 // Update line offset table
769 linetab[ypos] = d-(ypos<<2);
770 }
771
772
773 transpix = 0;
774
775 while(bitmap->data[s]==TRANSPARENT_IDX){
776 ++transpix;
777 ++s;
778 ++xpos;
779 if(xpos==width){
780 transpix -= width; // Return to startpos of line
781 dest->data[d>>2] = transpix;
782 d += 4;
783 dest->data[d>>2] = 0; // EOL marker (0 visible)
784 d += 4;
785 xpos = 0;
786 ++ypos;
787 goto ctn; // Re-enter loop
788 }
789 }
790
791 dest->data[d>>2] = transpix;
792 d+=4;
793
794
795 pos = s;
796 vispix = 0;
797 while(bitmap->data[pos]!=TRANSPARENT_IDX && xpos<width){
798 ++vispix;
799 ++xpos;
800 ++pos;
801 }
802 dest->data[d>>2] = vispix; // Store visible pixel count
803 d+=4;
804
805 for(pos=0; pos<vispix; pos++){ // Copy pixels
806 cdest[d++] = bitmap->data[s++];
807 }
808
809 while(d&3){ // Add alignment
810 cdest[d++] = 0;
811 }
812
813 if(xpos>=width){ // Stopped at end of line?
814 transpix = -width; // Back to startpos
815 dest->data[d>>2] = transpix;
816 d += 4;
817 dest->data[d>>2] = 0; // EOL marker (0 visible)
818 d += 4;
819 xpos = 0;
820 ++ypos;
821 }
822 }
823 return d; // Return size of new encoded sprite
824 }
825
826
827
828
829
830
831
832
833
834
835 // -------------------------- NEW: EFFECTS -------------------------------
836
837
838
839
840
841
842 /*
843 Same as above, but uses translation table.
844 */
ps_remap_bothclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)845 static void ps_remap_bothclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
846
847 int viscount, viscount_bytes;
848 unsigned long *data = linetab;
849 int clipcount;
850 unsigned char * charptr;
851 int widthcount;
852 unsigned char *dest_old;
853
854
855 // I know the x coord is negative! But this is OK anyway.
856 dest_c += y*screenwidth + x;
857
858 do{
859 // Get ready to draw a line
860 data = linetab + (*linetab / 4);
861 ++linetab;
862
863 dest_old = dest_c;
864 widthcount = screenwidth;
865
866 // The following for-loop contains code to skip the left offscreen
867 // area of the sprite. Complex shit, especially since it also has
868 // to clip on the right side now!
869
870 clipcount = x;
871 for(;;){
872
873 clipcount += *data; // Add clearcount
874 ++data;
875 if(clipcount >= 0){
876 // Reached on-screen area?
877 // Check if we've passed the screen entirely!
878 if(clipcount >= screenwidth) goto bclip_nextline_entry;
879
880 // Move the screen pointer to the left-most pixel on-screen.
881 dest_c -= x;
882 // Now add the clipcount overflow.
883 dest_c += clipcount;
884
885 // Keep the width counter in check.
886 widthcount -= clipcount;
887
888 goto bclip_entry1;
889 }
890
891
892 viscount = *data; // Get viscount
893 ++data;
894
895
896 if(viscount <= 0) goto bclip_nextline_entry; // Reached EOL?
897
898
899 if((viscount + clipcount) <= 0){
900 // These pixels can be safely skipped.
901 clipcount += viscount;
902
903 // Skip the pixels.
904 viscount += 3;
905 data += viscount>>2;
906
907 continue;
908 }
909
910
911 // The pixel run crosses the screen boundary!
912
913 charptr = (void*)data;
914
915 // Locate aligned position for frame pointer, past the pixels.
916 data += (viscount+3) >> 2;
917
918 // Move the screen pointer to the left-most pixel on-screen.
919 dest_c -= x;
920
921
922 charptr -= clipcount; // Find pixels to draw
923 viscount += clipcount; // How many pixels left to draw?
924
925 if(viscount >= screenwidth){
926 // Fill entire width of screen
927 viscount = screenwidth;
928 do{
929 *dest_c = lut[((int)(*charptr)) & 0xFF];
930 ++dest_c;
931 ++charptr;
932 }while(--viscount);
933
934 goto bclip_nextline_entry;
935 }
936
937 // Keep the width counter updated.
938 widthcount -= viscount;
939
940 // Draw this run's remaining pixels to the screen.
941 do{
942 *dest_c = lut[((int)(*charptr)) & 0xFF];
943 ++dest_c;
944 ++charptr;
945 }while(--viscount);
946
947 break; // Continue with right-clipped draw loop.
948 }
949
950
951 for(;;){
952 dest_c += *data; // Add clearcount
953 widthcount -= *data;
954 if(widthcount<=0) break; // Clip and go do the next line
955 ++data;
956
957 bclip_entry1:
958
959 viscount = *data;
960 ++data;
961
962
963 if(viscount<=0) break; // EOL
964
965
966 // If too many pixels to draw, cap run.
967 widthcount -= viscount;
968 if(widthcount<0) viscount += widthcount;
969
970 viscount_bytes = viscount;
971 charptr = (void*)data;
972 do{
973 *dest_c = lut[((int)(*charptr)) & 0xFF];
974 ++dest_c;
975 ++charptr;
976 }while(--viscount_bytes);
977 data += (viscount+3)>>2;
978
979
980 if(widthcount<=0) break; // Clip and go do the next line
981 };
982
983
984 bclip_nextline_entry:
985
986 dest_c = dest_old + screenwidth;
987
988 }while(--height);
989 }
990
991
992
993
994
995 /*
996 Right-side clipping.
997 Same as above, blah blah.
998 */
ps_remap_rightclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)999 static void ps_remap_rightclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
1000
1001 int viscount, viscount_bytes;
1002 unsigned long *data = linetab;
1003 int widthcount;
1004 unsigned char *dest_old;
1005 unsigned char *charptr;
1006
1007
1008 // Still visible?
1009 if(x >= screenwidth) return;
1010
1011
1012 // No need to check left-side clipping, should be done by leftclip code!
1013
1014
1015 // Get the screen pointer ready...
1016 dest_c += y*screenwidth + x;
1017
1018
1019 // Calculate the remaining width.
1020 width = screenwidth - x;
1021
1022
1023 do{
1024 // Get ready to draw a line
1025 data = linetab + (*linetab / 4);
1026 ++linetab;
1027
1028 dest_old = dest_c;
1029 widthcount = width;
1030
1031 for(;;){
1032 dest_c += *data; // Add clearcount
1033 widthcount -= *data;
1034 if(widthcount<=0) break; // Clip and go do the next line
1035 ++data;
1036
1037 viscount = *data;
1038 ++data;
1039
1040
1041 if(viscount<=0) break; // EOL
1042
1043
1044 // If too many pixels to draw, cap run.
1045 widthcount -= viscount;
1046 if(widthcount<0) viscount += widthcount;
1047
1048
1049 viscount_bytes = viscount;
1050 charptr = (void*)data;
1051 do{
1052 *dest_c = lut[((int)(*charptr)) & 0xFF];
1053 ++dest_c;
1054 ++charptr;
1055 }while(--viscount_bytes);
1056 data += (viscount+3)>>2;
1057
1058
1059 if(widthcount<=0) break; // Clip and go do the next line
1060 };
1061
1062 dest_c = dest_old + screenwidth;
1063
1064 }while(--height);
1065 }
1066
1067
1068
1069
1070 /*
1071 Left clipping for remap.
1072 */
ps_remap_leftclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)1073 static void ps_remap_leftclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
1074
1075 int viscount, viscount_bytes;
1076 unsigned long *data = linetab;
1077 int clipcount;
1078 unsigned char * charptr;
1079
1080
1081 // Still visible?
1082 if(-x >= width) return;
1083
1084
1085 // Check right clipping
1086 if(x+width > screenwidth){
1087 ps_remap_bothclip(x, y, width, height, data, dest_c, lut);
1088 return;
1089 }
1090
1091
1092 // I know the x coord is negative! But this is OK anyway.
1093 dest_c += y*screenwidth + x;
1094
1095 do{
1096 // Get ready to draw a line
1097 data = linetab + (*linetab / 4);
1098 ++linetab;
1099
1100
1101 // The following for-loop contains code to skip the left offscreen
1102 // area of the sprite. Complex shit!
1103
1104 clipcount = x;
1105 for(;;){
1106
1107 clipcount += *data; // Add clearcount
1108 ++data;
1109 if(clipcount >= 0){
1110 // Reached on-screen area!
1111 // Move the screen pointer to the left-most pixel on-screen.
1112 dest_c -= x;
1113 // Now add the clipcount overflow.
1114 dest_c += clipcount;
1115 goto lclip_entry1;
1116 }
1117
1118
1119 viscount = *data; // Get viscount
1120 ++data;
1121
1122
1123 if(viscount <= 0) goto lclip_nextline_entry; // Reached EOL?
1124
1125
1126 if((viscount + clipcount) <= 0){
1127 // These pixels can be safely skipped.
1128 clipcount += viscount;
1129
1130 // Skip the pixels.
1131 viscount += 3;
1132 data += viscount>>2;
1133
1134 continue;
1135 }
1136
1137
1138 // The pixel run crosses the screen boundary!
1139
1140 charptr = (void*)data;
1141
1142 // Locate aligned position for source data pointer, past the pixels.
1143 data += (viscount+3) >> 2;
1144
1145 charptr -= clipcount; // Find pixels to draw
1146 viscount += clipcount; // How many pixels left to draw?
1147
1148 // Move the screen pointer to the left-most pixel on-screen.
1149 dest_c -= x;
1150
1151 // Draw this run's remaining pixels to the screen.
1152 do{
1153 *dest_c = lut[((int)(*charptr)) & 0xFF];
1154 ++dest_c;
1155 ++charptr;
1156 }while(--viscount);
1157
1158 break; // Continue with normal draw loop.
1159 }
1160
1161
1162 // Normal draw loop...
1163 for(;;){
1164 dest_c += *data; // Add clearcount
1165 ++data;
1166
1167 lclip_entry1:
1168
1169 viscount = *data;
1170 ++data;
1171
1172 if(viscount<=0) break;
1173
1174 viscount_bytes = viscount;
1175 charptr = (void*)data;
1176 do{
1177 *dest_c = lut[((int)(*charptr)) & 0xFF];
1178 ++dest_c;
1179 ++charptr;
1180 }while(--viscount_bytes);
1181 data += (viscount+3)>>2;
1182 };
1183
1184 lclip_nextline_entry:
1185
1186 dest_c += screenwidth;
1187
1188 }while(--height);
1189 }
1190
1191
1192
1193
1194 // Putsprite function with remapping
putsprite_remap(int x,int y,s_sprite * frame,s_screen * screen,unsigned char * lut)1195 void putsprite_remap(int x, int y, s_sprite *frame, s_screen *screen, unsigned char *lut){
1196
1197 unsigned long *linetab;
1198 int width, height;
1199 int viscount, viscount_bytes;
1200 unsigned long *data;
1201 unsigned char *dest_c;
1202 unsigned char *charptr;
1203
1204
1205 // Get screen size
1206 screenwidth = screen->width;
1207 screenheight = screen->height;
1208
1209 dest_c = screen->data;
1210
1211
1212 // Adjust coords for centering
1213 x -= frame->centerx;
1214 y -= frame->centery;
1215
1216
1217 // Get sprite dimensions
1218 width = frame->width;
1219 height = frame->height;
1220
1221
1222 // Check if sprite dimensions are valid
1223 if(width<=0 || height<=0) return;
1224
1225
1226 // Init line table pointer
1227 linetab = (void*)frame->data;
1228
1229
1230 // Check clipping, vertical first
1231 if(y < 0){
1232 // Clip top
1233 height += y; // Make sprite shorter
1234 if(height <=0 ) return;
1235 linetab -= y; // Advance -y lines
1236 y = 0;
1237 }
1238 if(y+height > screenheight){
1239 // Clip bottom (make sprite shorter)
1240 height = screenheight - y;
1241 if(height <= 0) return;
1242 }
1243 if(x < 0){
1244 // Clip left
1245 ps_remap_leftclip(x, y, width, height, linetab, dest_c, lut);
1246 return;
1247 }
1248 if(x+width > screenwidth){
1249 // Clip right
1250 ps_remap_rightclip(x, y, width, height, linetab, dest_c, lut);
1251 return;
1252 }
1253
1254
1255 dest_c += y*screenwidth + x;
1256
1257
1258 do{
1259 // Get ready to draw a line
1260 data = linetab + (*linetab / 4);
1261 ++linetab;
1262
1263 for(;;){
1264 dest_c += *data; // Add clearcount
1265 ++data;
1266
1267 viscount = *data;
1268 ++data;
1269
1270 if(viscount<=0) break;
1271
1272 viscount_bytes = viscount;
1273 charptr = (void*)data;
1274 do{
1275 *dest_c = lut[((int)(*charptr)) & 0xFF];
1276 ++dest_c;
1277 ++charptr;
1278 }while(--viscount_bytes);
1279 data += (viscount+3)>>2;
1280 };
1281
1282 dest_c += screenwidth;
1283
1284 }while(--height);
1285 }
1286
1287
1288
1289
1290
1291
1292
1293
1294 /*
1295 Now with blending...
1296 */
ps_blend_bothclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)1297 static void ps_blend_bothclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
1298
1299 int viscount, viscount_bytes;
1300 unsigned long *data = linetab;
1301 int clipcount;
1302 unsigned char * charptr;
1303 int widthcount;
1304 unsigned char *dest_old;
1305
1306
1307 // I know the x coord is negative! But this is OK anyway.
1308 dest_c += y*screenwidth + x;
1309
1310 do{
1311 // Get ready to draw a line
1312 data = linetab + (*linetab / 4);
1313 ++linetab;
1314
1315 dest_old = dest_c;
1316 widthcount = screenwidth;
1317
1318 // The following for-loop contains code to skip the left offscreen
1319 // area of the sprite. Complex shit, especially since it also has
1320 // to clip on the right side now!
1321
1322 clipcount = x;
1323 for(;;){
1324
1325 clipcount += *data; // Add clearcount
1326 ++data;
1327 if(clipcount >= 0){
1328 // Reached on-screen area?
1329 // Check if we've passed the screen entirely!
1330 if(clipcount >= screenwidth) goto bclip_nextline_entry;
1331
1332 // Move the screen pointer to the left-most pixel on-screen.
1333 dest_c -= x;
1334 // Now add the clipcount overflow.
1335 dest_c += clipcount;
1336
1337 // Keep the width counter in check.
1338 widthcount -= clipcount;
1339
1340 goto bclip_entry1;
1341 }
1342
1343
1344 viscount = *data; // Get viscount
1345 ++data;
1346
1347
1348 if(viscount <= 0) goto bclip_nextline_entry; // Reached EOL?
1349
1350
1351 if((viscount + clipcount) <= 0){
1352 // These pixels can be safely skipped.
1353 clipcount += viscount;
1354
1355 // Skip the pixels.
1356 viscount += 3;
1357 data += viscount>>2;
1358
1359 continue;
1360 }
1361
1362
1363 // The pixel run crosses the screen boundary!
1364
1365 charptr = (void*)data;
1366
1367 // Locate aligned position for frame pointer, past the pixels.
1368 data += (viscount+3) >> 2;
1369
1370 // Move the screen pointer to the left-most pixel on-screen.
1371 dest_c -= x;
1372
1373
1374 charptr -= clipcount; // Find pixels to draw
1375 viscount += clipcount; // How many pixels left to draw?
1376
1377 if(viscount >= screenwidth){
1378 // Fill entire width of screen
1379 viscount = screenwidth;
1380 do{
1381 *dest_c = lut[(*charptr<<8) | *dest_c];
1382 ++dest_c;
1383 ++charptr;
1384 }while(--viscount);
1385
1386 goto bclip_nextline_entry;
1387 }
1388
1389 // Keep the width counter updated.
1390 widthcount -= viscount;
1391
1392 // Draw this run's remaining pixels to the screen.
1393 do{
1394 *dest_c = lut[(*charptr<<8) | *dest_c];
1395 ++dest_c;
1396 ++charptr;
1397 }while(--viscount);
1398
1399 break; // Continue with right-clipped draw loop.
1400 }
1401
1402
1403 for(;;){
1404 dest_c += *data; // Add clearcount
1405 widthcount -= *data;
1406 if(widthcount<=0) break; // Clip and go do the next line
1407 ++data;
1408
1409 bclip_entry1:
1410
1411 viscount = *data;
1412 ++data;
1413
1414
1415 if(viscount<=0) break; // EOL
1416
1417
1418 // If too many pixels to draw, cap run.
1419 widthcount -= viscount;
1420 if(widthcount<0) viscount += widthcount;
1421
1422 viscount_bytes = viscount;
1423 charptr = (void*)data;
1424 do{
1425 *dest_c = lut[(*charptr<<8) | *dest_c];
1426 ++dest_c;
1427 ++charptr;
1428 }while(--viscount_bytes);
1429 data += (viscount+3)>>2;
1430
1431
1432 if(widthcount<=0) break; // Clip and go do the next line
1433 };
1434
1435
1436 bclip_nextline_entry:
1437
1438 dest_c = dest_old + screenwidth;
1439
1440 }while(--height);
1441 }
1442
1443
1444
1445
1446
1447 /*
1448 Right-side clipping.
1449 Same as above, blah blah.
1450 */
ps_blend_rightclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)1451 static void ps_blend_rightclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
1452
1453 int viscount, viscount_bytes;
1454 unsigned long *data = linetab;
1455 int widthcount;
1456 unsigned char *dest_old;
1457 unsigned char *charptr;
1458
1459
1460 // Still visible?
1461 if(x >= screenwidth) return;
1462
1463
1464 // No need to check left-side clipping, should be done by leftclip code!
1465
1466
1467 // Get the screen pointer ready...
1468 dest_c += y*screenwidth + x;
1469
1470
1471 // Calculate the remaining width.
1472 width = screenwidth - x;
1473
1474
1475 do{
1476 // Get ready to draw a line
1477 data = linetab + (*linetab / 4);
1478 ++linetab;
1479
1480 dest_old = dest_c;
1481 widthcount = width;
1482
1483 for(;;){
1484 dest_c += *data; // Add clearcount
1485 widthcount -= *data;
1486 if(widthcount<=0) break; // Clip and go do the next line
1487 ++data;
1488
1489 viscount = *data;
1490 ++data;
1491
1492
1493 if(viscount<=0) break; // EOL
1494
1495
1496 // If too many pixels to draw, cap run.
1497 widthcount -= viscount;
1498 if(widthcount<0) viscount += widthcount;
1499
1500
1501 viscount_bytes = viscount;
1502 charptr = (void*)data;
1503 do{
1504 *dest_c = lut[(*charptr<<8) | *dest_c];
1505 ++dest_c;
1506 ++charptr;
1507 }while(--viscount_bytes);
1508 data += (viscount+3)>>2;
1509
1510
1511 if(widthcount<=0) break; // Clip and go do the next line
1512 };
1513
1514 dest_c = dest_old + screenwidth;
1515
1516 }while(--height);
1517 }
1518
1519
1520
1521
1522 /*
1523 Left clipping for remap.
1524 */
ps_blend_leftclip(int x,int y,int width,int height,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut)1525 static void ps_blend_leftclip(int x, int y, int width, int height, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut){
1526
1527 int viscount, viscount_bytes;
1528 unsigned long *data = linetab;
1529 int clipcount;
1530 unsigned char * charptr;
1531
1532
1533 // Still visible?
1534 if(-x >= width) return;
1535
1536
1537 // Check right clipping
1538 if(x+width > screenwidth){
1539 ps_blend_bothclip(x, y, width, height, data, dest_c, lut);
1540 return;
1541 }
1542
1543
1544 // I know the x coord is negative! But this is OK anyway.
1545 dest_c += y*screenwidth + x;
1546
1547 do{
1548 // Get ready to draw a line
1549 data = linetab + (*linetab / 4);
1550 ++linetab;
1551
1552
1553 // The following for-loop contains code to skip the left offscreen
1554 // area of the sprite. Complex shit!
1555
1556 clipcount = x;
1557 for(;;){
1558
1559 clipcount += *data; // Add clearcount
1560 ++data;
1561 if(clipcount >= 0){
1562 // Reached on-screen area!
1563 // Move the screen pointer to the left-most pixel on-screen.
1564 dest_c -= x;
1565 // Now add the clipcount overflow.
1566 dest_c += clipcount;
1567 goto lclip_entry1;
1568 }
1569
1570
1571 viscount = *data; // Get viscount
1572 ++data;
1573
1574
1575 if(viscount <= 0) goto lclip_nextline_entry; // Reached EOL?
1576
1577
1578 if((viscount + clipcount) <= 0){
1579 // These pixels can be safely skipped.
1580 clipcount += viscount;
1581
1582 // Skip the pixels.
1583 viscount += 3;
1584 data += viscount>>2;
1585
1586 continue;
1587 }
1588
1589
1590 // The pixel run crosses the screen boundary!
1591
1592 charptr = (void*)data;
1593
1594 // Locate aligned position for source data pointer, past the pixels.
1595 data += (viscount+3) >> 2;
1596
1597 charptr -= clipcount; // Find pixels to draw
1598 viscount += clipcount; // How many pixels left to draw?
1599
1600 // Move the screen pointer to the left-most pixel on-screen.
1601 dest_c -= x;
1602
1603 // Draw this run's remaining pixels to the screen.
1604 do{
1605 *dest_c = lut[(*charptr<<8) | *dest_c];
1606 ++dest_c;
1607 ++charptr;
1608 }while(--viscount);
1609
1610 break; // Continue with normal draw loop.
1611 }
1612
1613
1614 // Normal draw loop...
1615 for(;;){
1616 dest_c += *data; // Add clearcount
1617 ++data;
1618
1619 lclip_entry1:
1620
1621 viscount = *data;
1622 ++data;
1623
1624 if(viscount<=0) break;
1625
1626 viscount_bytes = viscount;
1627 charptr = (void*)data;
1628 do{
1629 *dest_c = lut[(*charptr<<8) | *dest_c];
1630 ++dest_c;
1631 ++charptr;
1632 }while(--viscount_bytes);
1633 data += (viscount+3)>>2;
1634 };
1635
1636 lclip_nextline_entry:
1637
1638 dest_c += screenwidth;
1639
1640 }while(--height);
1641 }
1642
1643
1644
1645
1646 // Putsprite function with remapping
putsprite_blend(int x,int y,s_sprite * frame,s_screen * screen,unsigned char * lut)1647 void putsprite_blend(int x, int y, s_sprite *frame, s_screen *screen, unsigned char *lut){
1648
1649 unsigned long *linetab;
1650 int width, height;
1651 int viscount, viscount_bytes;
1652 unsigned long *data;
1653 unsigned char *dest_c;
1654 unsigned char *charptr;
1655
1656
1657 // Get screen size
1658 screenwidth = screen->width;
1659 screenheight = screen->height;
1660
1661 dest_c = screen->data;
1662
1663
1664 // Adjust coords for centering
1665 x -= frame->centerx;
1666 y -= frame->centery;
1667
1668
1669 // Get sprite dimensions
1670 width = frame->width;
1671 height = frame->height;
1672
1673
1674 // Check if sprite dimensions are valid
1675 if(width<=0 || height<=0) return;
1676
1677
1678 // Init line table pointer
1679 linetab = (void*)frame->data;
1680
1681
1682 // Check clipping, vertical first
1683 if(y < 0){
1684 // Clip top
1685 height += y; // Make sprite shorter
1686 if(height <=0 ) return;
1687 linetab -= y; // Advance -y lines
1688 y = 0;
1689 }
1690 if(y+height > screenheight){
1691 // Clip bottom (make sprite shorter)
1692 height = screenheight - y;
1693 if(height <= 0) return;
1694 }
1695 if(x < 0){
1696 // Clip left
1697 ps_blend_leftclip(x, y, width, height, linetab, dest_c, lut);
1698 return;
1699 }
1700 if(x+width > screenwidth){
1701 // Clip right
1702 ps_blend_rightclip(x, y, width, height, linetab, dest_c, lut);
1703 return;
1704 }
1705
1706
1707 dest_c += y*screenwidth + x;
1708
1709
1710 do{
1711 // Get ready to draw a line
1712 data = linetab + (*linetab / 4);
1713 ++linetab;
1714
1715 for(;;){
1716 dest_c += *data; // Add clearcount, startx
1717 ++data;
1718
1719 viscount = *data; // length
1720 ++data;
1721
1722 if(viscount<=0) break;
1723
1724 viscount_bytes = viscount;
1725 charptr = (void*)data;
1726 do{
1727 *dest_c = lut[(*charptr<<8) | *dest_c];
1728 ++dest_c;
1729 ++charptr;
1730 }while(--viscount_bytes);
1731 data += (viscount+3)>>2; // next block
1732 };
1733
1734 dest_c += screenwidth;
1735
1736 }while(--height);
1737 }
1738
1739 static unsigned char fillcolor=0;
1740
remapcolor(unsigned char * table,unsigned char color,unsigned char unused)1741 unsigned char remapcolor(unsigned char* table, unsigned char color, unsigned char unused)
1742 {
1743 return table[color];
1744 }
1745
blendcolor(unsigned char * table,unsigned char color1,unsigned char color2)1746 unsigned char blendcolor(unsigned char* table, unsigned char color1, unsigned char color2)
1747 {
1748 if(!table) return color1;
1749 return table[color1<<8|color2];
1750 }
1751
blendfillcolor(unsigned char * table,unsigned char unused,unsigned char color)1752 unsigned char blendfillcolor(unsigned char* table, unsigned char unused, unsigned char color)
1753 {
1754 if(!table) return fillcolor;
1755 return table[fillcolor<<8|color];
1756 }
1757
1758
1759 //--------------------------------------------------------------------------------------
1760
1761 // x: centerx on screen cx: centerx of this line
scaleline(int x,int cx,int width,unsigned long * linetab,unsigned char * dest_c,unsigned char * lut,transpixelfunc fp,unsigned int scale)1762 static void scaleline(int x, int cx, int width, unsigned long *linetab, unsigned char *dest_c, unsigned char *lut, transpixelfunc fp, unsigned int scale)
1763 {
1764 unsigned long *data = linetab;
1765 int dx, i, d;
1766 unsigned char * charptr;
1767 unsigned int scale_d=0, old_scale_d=0, cleft, cwidth;
1768
1769 dx = x - ((cx*scale)>>8); //draw start x
1770
1771 // if(dx>=screenwidth || dx+((width*scale)>>8)<0) return; it should be check in the function that called this
1772
1773 dest_c += dx;
1774
1775 // Get ready to draw a line
1776 data = linetab + (*linetab / 4);
1777
1778 for(;;)
1779 {
1780 cleft = *data++;
1781 cwidth = *data++;
1782 if(cwidth<=0) return; // end of line
1783 //scale_s += cleft<<8; // src scale, 256
1784 charptr = (unsigned char*)data;
1785 data += (cwidth+3)>>2; // skip some bytes to next block
1786 scale_d += cleft*scale; // dest scale, scale
1787 dx += cleft;
1788 if(dx>=screenwidth) return; // out of right border? exit
1789 d = scale_d - old_scale_d;
1790 if(d >= 256) // skip some blank pixels
1791 {
1792 dest_c += d>>8;
1793 old_scale_d = (scale_d>>8)<<8;
1794 }
1795 while(cwidth--) // draw these pixels
1796 {
1797 scale_d += scale;
1798 d = scale_d - old_scale_d; // count scale added
1799 if(d >= 256) // > 1pixel, so draw these
1800 {
1801 for(i=d>>8; i>0; i--) // draw a pixel
1802 {
1803 if(dx>=0) // pass left border?
1804 {
1805 *dest_c = fp(lut, *charptr, *dest_c);
1806 }
1807 if(++dx>=screenwidth) return; // out of right border? exit
1808 dest_c++; // position move to right one pixel
1809 }
1810 old_scale_d = (scale_d>>8)<<8; //truncate those less than 256
1811 }
1812 charptr++; // src ptr move right one pixel
1813 }
1814 }
1815
1816 }
1817
1818
1819
1820
1821 // scalex scaley flipy ...
putsprite_ex(int x,int y,s_sprite * frame,s_screen * screen,s_drawmethod * drawmethod)1822 void putsprite_ex(int x, int y, s_sprite *frame, s_screen *screen, s_drawmethod* drawmethod)
1823 {
1824 unsigned long *linetab;
1825 int height, dx, d, i, cy;
1826 unsigned char *dest_c;
1827 int scale=0, old_scale=0;
1828
1829 if(!drawmethod)
1830 {
1831 putsprite(x, y, frame, screen);
1832 return;
1833 }
1834
1835 if(!drawmethod->scalex || !drawmethod->scaley) return; // zero size
1836
1837 screenheight = screen->height;
1838 screenwidth = screen->width;
1839
1840 dx = x - ((frame->centerx*drawmethod->scalex)>>8); //draw start x
1841
1842 if(dx>=screenwidth || dx+((frame->width*drawmethod->scalex)>>8)<0) return; // out of left or right border
1843
1844 cy = y;
1845 height = frame->height;
1846 linetab = (unsigned long*)(frame->data);
1847
1848 if(drawmethod->fillcolor) fillcolor = drawmethod->fillcolor;
1849
1850 // flip in y direction, from centery
1851 if(drawmethod->flipy)
1852 {
1853 y += (frame->centery*drawmethod->scaley)>>8; // lowest
1854 dest_c = (unsigned char*)(screen->data)+y*screenwidth;
1855 if(y<0) return;
1856
1857 while(height--)
1858 {
1859 scale += drawmethod->scaley;
1860 d = scale - old_scale; // count scale added
1861 if(d >= 256) // > 1pixel, so draw these
1862 {
1863 for(i=d>>8; i>0; i--) // draw a line
1864 {
1865 if(y<screenheight) // pass lower border?
1866 {
1867 scaleline(x+((drawmethod->shiftx*(cy-y))/256), frame->centerx, frame->width, linetab, dest_c, drawmethod->table, drawmethod->fp, drawmethod->scalex);
1868 }
1869 if(--y<0) return; // out of lower border? exit
1870 dest_c -= screenwidth; // position move down one line
1871 }
1872 old_scale = (scale>>8)<<8; //truncate those less than 256
1873 }
1874 linetab++; //src line shift
1875 }
1876 }
1877 else // un-flipped version
1878 {
1879 y -= (frame->centery*drawmethod->scaley)>>8; // topmost
1880 dest_c = (unsigned char*)(screen->data)+y*screenwidth;
1881 if(y>=screenheight) return;
1882
1883 while(height--)
1884 {
1885 scale += drawmethod->scaley;
1886 d = scale - old_scale; // count scale added
1887 if(d >= 256) // > 1pixel, so draw these
1888 {
1889 for(i=d>>8; i>0; i--) // draw a line
1890 {
1891 if(y>=0) // pass upper border?
1892 {
1893 scaleline(x+((drawmethod->shiftx*(y-cy))/256), frame->centerx, frame->width, linetab, dest_c, drawmethod->table, drawmethod->fp, drawmethod->scalex);
1894 }
1895 if(++y>=screenheight) return; // out of lower border? exit
1896 dest_c += screenwidth; // position move down one line
1897 }
1898 old_scale = (scale>>8)<<8; //truncate those less than 256
1899 }
1900 linetab++; //src line shift
1901 }
1902 }
1903 }
1904