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