1 /*
2  * Copyright (c) 2000,2001 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 #ifdef _WIN32
20 #include "win32/config.h"
21 #else
22 #include "config.h"
23 #endif
24 
25 /*#define LOCAL_DEBUG*/
26 /*#define DO_CLOCKING*/
27 
28 #ifdef HAVE_MMX
29 #include <mmintrin.h>
30 #endif
31 
32 #include <ctype.h>
33 #ifdef _WIN32
34 # include "win32/afterbase.h"
35 #else
36 # include "afterbase.h"
37 #endif
38 #include "asvisual.h"
39 #include "scanline.h"
40 #include "blender.h"
41 
42 /*********************************************************************************/
43 /* colorspace conversion functions : 											 */
44 /*********************************************************************************/
45 
46 CARD32
rgb2value(CARD32 red,CARD32 green,CARD32 blue)47 rgb2value( CARD32 red, CARD32 green, CARD32 blue )
48 {
49 	if( red > green )
50 		return MAX(red,blue);
51 	return MAX(green, blue);
52 }
53 
54 CARD32
rgb2saturation(CARD32 red,CARD32 green,CARD32 blue)55 rgb2saturation( CARD32 red, CARD32 green, CARD32 blue )
56 {
57 	register int max_val, min_val ;
58 	if( red > green )
59 	{
60 		max_val = MAX(red,blue);
61 		min_val = MIN(green,blue);
62 	}else
63 	{
64 		max_val = MAX(green, blue) ;
65 		min_val = MIN(red,blue) ;
66 	}
67 	return max_val > 1 ? ((max_val - min_val)<<15)/(max_val>>1) : 0;
68 }
69 
70 
71 /* Traditionally Hue is represented by 360 degree circle.
72   For our needs we use 255 degree circle instead.
73 
74   Now the circle is separated into 6 segments :
75   Trad:		Us:				Color range:    Red:	Green:	Blue:
76   0-60		0    -42.5 		red-yellow      FF-7F   0 -7F   0 -0
77   60-120    42.5 -85 		yellow-green    7F-0    7F-FF   0 -0
78   120-180   85   -127.5 	green-cyan      0 -0    FF-7F   0 -7F
79   180-240   127.5-170   	cyan-blue       0 -0    7F-0    7F-FF
80   240-300   170  -212.5     blue-magenta    0-7F    0 -0	FF-7F
81   300-360   212.5-255       magenta-red     7F-FF   0 -0    7F-0
82 
83   As seen from above in each segment at least one of the RGB values is 0.
84   To achieve that we find minimum of R, G and b and substract it from all,
85   and then multiply values by ratio to bring it into range :
86 
87   new_val = ((val - min_val)*0xFEFF)/(max_val-min_val)
88   (note that we use 16bit values, instead of 8 bit as above)
89 
90   WE store hue in 16 bits, so instead of above value of 42.5 per segment
91   we should use 85<<7 == 0x00002A80 per segment.
92 
93   When all the RGB values are the same - then hue is invalid and  = 0;
94   To distinguish between hue == 0 when color is Red and invalid hue, we
95   make all valid hues to fit in range 0x0001-0xFF00, with 0x0001 being RED.
96 */
97 
98 #define HUE_RED_TO_YELLOW		0
99 #define HUE_YELLOW_TO_GREEN		1
100 #define HUE_GREEN_TO_CYAN   	2
101 #define HUE_CYAN_TO_BLUE    	3
102 #define HUE_BLUE_TO_MAGENTA   	4
103 #define HUE_MAGENTA_TO_RED   	5
104 
105 #define HUE16_RED				(HUE16_RANGE*HUE_RED_TO_YELLOW)
106 #define HUE16_YELLOW			(HUE16_RANGE*HUE_YELLOW_TO_GREEN)
107 #define HUE16_GREEN			   	(HUE16_RANGE*HUE_GREEN_TO_CYAN)
108 #define HUE16_CYAN		    	(HUE16_RANGE*HUE_CYAN_TO_BLUE)
109 #define HUE16_BLUE			   	(HUE16_RANGE*HUE_BLUE_TO_MAGENTA)
110 #define HUE16_MAGENTA		 	(HUE16_RANGE*HUE_MAGENTA_TO_RED)
111 
112 #define MAKE_HUE16(hue,red,green,blue,min_val,max_val,delta) \
113 	do{	if( (red) == (max_val) ){ /* 300 to 60 degrees segment */ \
114 			if( (blue) <= (green) ){  /* 0-60 degrees segment*/    \
115 				(hue) = HUE16_RED    + (((green) - (blue)) * (HUE16_RANGE)) / (delta) ;\
116 				if( (hue) == 0 ) (hue) = MIN_HUE16 ; \
117 			}else {	               /* 300-0 degrees segment*/ \
118 				(hue) = HUE16_MAGENTA+ (((red)   - (blue)) * (HUE16_RANGE)) / (delta) ; \
119 				if( (hue) == 0 ) (hue) = MAX_HUE16 ;                                 \
120 			}                                                                   \
121 		}else if( (green) == (max_val) ){ /* 60 to 180 degrees segment */           \
122 			if( (blue) >= (red) )    /* 120-180 degrees segment*/                   \
123 				(hue) = HUE16_GREEN  + (((blue)-(red) ) * (HUE16_RANGE)) / (delta) ;    \
124 			else                 /* 60-120 degrees segment */                   \
125 				(hue) = HUE16_YELLOW + (((green)-(red)) * (HUE16_RANGE)) / (delta) ;    \
126 		}else if( (red) >= (green) )     /* 240 to 300 degrees segment */           \
127 			(hue)     = HUE16_BLUE   + (((red) -(green))* (HUE16_RANGE)) / (delta) ;    \
128 		else                        /* 180 to 240 degrees segment */            \
129 			(hue)     = HUE16_CYAN   + (((blue)-(green))* (HUE16_RANGE)) / (delta) ;    \
130 	}while(0)
131 #define INTERPRET_HUE16(hue,delta,max_val,red,green,blue)      \
132 	do{	int range = (hue)/HUE16_RANGE ;                                  \
133 		int min_val = (max_val) - (delta);                                \
134 		int mid_val = ((hue) - HUE16_RANGE*range)*(delta) / HUE16_RANGE ;  \
135 		switch( range )	{                                              \
136 			case HUE_RED_TO_YELLOW :    /* red was max, then green  */ \
137 				(red)   = (max_val); (green)=mid_val+(min_val); (blue) = (min_val); break; \
138 			case HUE_YELLOW_TO_GREEN :  /* green was max, then red */                      \
139 				(green) = (max_val); (red) =(max_val)-mid_val;  (blue) = (min_val); break; \
140 			case HUE_GREEN_TO_CYAN :    /* green was max, then blue*/                      \
141 				(green) = (max_val); (blue)= mid_val+(min_val);	(red)  = (min_val); break; \
142 			case HUE_CYAN_TO_BLUE :     /* blue was max, then green  */                    \
143 				(blue)  = (max_val); (green)=(max_val)-mid_val; (red)  = (min_val); break; \
144 			case HUE_BLUE_TO_MAGENTA :  /* blue was max, then red   */                     \
145 				(blue)  = (max_val); (red)  = mid_val+(min_val);(green)= (min_val); break; \
146 			case HUE_MAGENTA_TO_RED :   /* red was max, then blue */                       \
147 				(red)   = (max_val); (blue) = (max_val)-mid_val;(green)= (min_val); break; \
148 		}                                                                                  \
149 	}while(0)
150 
151 
normalize_degrees_val(int degrees)152 int normalize_degrees_val( int degrees )
153 {
154 	while ( degrees < 0 ) degrees += 360 ;
155 	while ( degrees >= 360 ) degrees -= 360 ;
156 	return degrees;
157 }
158 
159 CARD32
degrees2hue16(int degrees)160 degrees2hue16( int degrees )
161 {
162 	CARD32 hue = 0 ;
163 
164 	while ( degrees < 0 ) degrees += 360 ;
165 	while ( degrees >= 360 ) degrees -= 360 ;
166 
167 	hue = degrees * HUE16_RANGE / 60 ;
168 	return (hue==0)?MIN_HUE16:hue ;
169 }
170 
171 int
hue162degrees(CARD32 hue)172 hue162degrees( CARD32 hue )
173 {
174 	if( hue < MIN_HUE16 || hue > MAX_HUE16 )
175 		return -1 ;
176 
177 	return (hue*60)/HUE16_RANGE ;
178 }
179 
180 CARD32
rgb2hue(CARD32 red,CARD32 green,CARD32 blue)181 rgb2hue( CARD32 red, CARD32 green, CARD32 blue )
182 {
183 	int max_val, min_val, hue = 0 ;
184 	if( red > green )
185 	{
186 		max_val = MAX(red,blue);
187 		min_val = MIN(green,blue);
188 	}else
189 	{
190 		max_val = MAX(green,blue);
191 		min_val = MIN(red,blue);
192 	}
193 	if( max_val != min_val)
194 	{
195 		int delta = max_val-min_val ;
196 		MAKE_HUE16(hue,(int)red,(int)green,(int)blue,min_val,max_val,delta);
197 	}
198 	return hue;
199 }
200 
201 CARD32
rgb2hsv(CARD32 red,CARD32 green,CARD32 blue,CARD32 * saturation,CARD32 * value)202 rgb2hsv( CARD32 red, CARD32 green, CARD32 blue, CARD32 *saturation, CARD32 *value )
203 {
204 	int max_val, min_val, hue = 0 ;
205 	if( red > green )
206 	{
207 		max_val = MAX(red,blue);
208 		min_val = MIN(green,blue);
209 	}else
210 	{
211 		max_val = MAX(green,blue);
212 		min_val = MIN(red,blue);
213 	}
214 	*value = max_val ;
215 	if( max_val != min_val)
216 	{
217 		int delta = max_val-min_val ;
218 		*saturation = (max_val>1)?(delta<<15)/(max_val>>1): 0;
219 		MAKE_HUE16(hue,(int)red,(int)green,(int)blue,min_val,max_val,delta);
220 	}else
221 		*saturation = 0 ;
222 	return hue;
223 }
224 
225 void
hsv2rgb(CARD32 hue,CARD32 saturation,CARD32 value,CARD32 * red,CARD32 * green,CARD32 * blue)226 hsv2rgb (CARD32 hue, CARD32 saturation, CARD32 value, CARD32 *red, CARD32 *green, CARD32 *blue)
227 {
228 	if (saturation == 0 || hue == 0 )
229 	{
230     	*blue = *green = *red = value;
231 	}else
232 	{
233 		int delta = ((saturation*(value>>1))>>15) ;
234 		INTERPRET_HUE16(hue,delta,value,*red,*green,*blue);
235 	}
236 }
237 
238 CARD32                                         /* returns luminance */
rgb2luminance(CARD32 red,CARD32 green,CARD32 blue)239 rgb2luminance (CARD32 red, CARD32 green, CARD32 blue )
240 {
241 	int max_val, min_val;
242 	if( red > green )
243 	{
244 		max_val = MAX(red,blue);
245 		min_val = MIN(green,blue);
246 	}else
247 	{
248 		max_val = MAX(green,blue);
249 		min_val = MIN(red,blue);
250 	}
251 	return (max_val+min_val)>>1;
252 }
253 
254 CARD32                                         /* returns hue */
rgb2hls(CARD32 red,CARD32 green,CARD32 blue,CARD32 * luminance,CARD32 * saturation)255 rgb2hls (CARD32 red, CARD32 green, CARD32 blue, CARD32 *luminance, CARD32 *saturation )
256 {
257 	int max_val, min_val, hue = 0 ;
258 	if( red > green )
259 	{
260 		max_val = MAX(red,blue);
261 		min_val = MIN(green,blue);
262 	}else
263 	{
264 		max_val = MAX(green,blue);
265 		min_val = MIN(red,blue);
266 	}
267 	*luminance = (max_val+min_val)>>1;
268 
269 	if( max_val != min_val )
270 	{
271 		int delta = max_val-min_val ;
272 		if( *luminance == 0 ) ++(*luminance);
273 		else if( *luminance == 0x0000FFFF ) --(*luminance);
274 		*saturation = (*luminance < 0x00008000 )?
275 							(delta<<15)/ *luminance :
276 							(delta<<15)/ (0x0000FFFF - *luminance);
277 		MAKE_HUE16(hue,(int)red,(int)green,(int)blue,min_val,max_val,delta);
278 	}else
279 		*saturation = 0 ;
280 	return hue;
281 }
282 
283 void
hls2rgb(CARD32 hue,CARD32 luminance,CARD32 saturation,CARD32 * red,CARD32 * green,CARD32 * blue)284 hls2rgb (CARD32 hue, CARD32 luminance, CARD32 saturation, CARD32 *red, CARD32 *green, CARD32 *blue)
285 {
286 	if (saturation == 0)
287 	{
288     	*blue = *green = *red = luminance;
289 	}else
290 	{
291 		int delta = ( luminance < 0x00008000 )?
292 						(saturation*luminance)>>15 :
293 	                    (saturation*(0x0000FFFF-luminance))>>15 ;
294 		int max_val = delta+(((luminance<<1)-delta)>>1) ;
295 
296 		INTERPRET_HUE16(hue,delta,max_val,*red,*green,*blue);
297 	}
298 }
299 
300 /*************************************************************************/
301 /* scanline blending 													 */
302 /*************************************************************************/
303 
304 typedef struct merge_scanlines_func_desc {
305     char *name ;
306 	int name_len ;
307 	merge_scanlines_func func;
308 	char *short_desc;
309 }merge_scanlines_func_desc;
310 
311 merge_scanlines_func_desc std_merge_scanlines_func_list[] =
312 {
313   { "add", 3, add_scanlines, "color addition with saturation" },
314   { "alphablend", 10, alphablend_scanlines, "alpha-blending" },
315   { "allanon", 7, allanon_scanlines, "color values averaging" },
316   { "colorize", 8, colorize_scanlines, "hue and saturate bottom image same as top image" },
317   { "darken", 6, darken_scanlines, "use lowest color value from both images" },
318   { "diff", 4, diff_scanlines, "use absolute value of the color difference between two images" },
319   { "dissipate", 9, dissipate_scanlines, "randomly alpha-blend images"},
320   { "hue", 3, hue_scanlines, "hue bottom image same as top image"  },
321   { "lighten", 7, lighten_scanlines, "use highest color value from both images" },
322   { "overlay", 7, overlay_scanlines, "some wierd image overlaying(see GIMP)" },
323   { "saturate", 8, saturate_scanlines, "saturate bottom image same as top image"},
324   { "screen", 6, screen_scanlines, "another wierd image overlaying(see GIMP)" },
325   { "sub", 3, sub_scanlines, "color substraction with saturation" },
326   { "tint", 4, tint_scanlines, "tinting image with image" },
327   { "value", 5, value_scanlines, "value bottom image same as top image" },
328   { NULL, 0, NULL }
329 };
330 
331 merge_scanlines_func
blend_scanlines_name2func(const char * name)332 blend_scanlines_name2func( const char *name )
333 {
334 	register int i = 0;
335 
336 	if( name == NULL )
337 		return NULL ;
338     while( isspace((int)*name) ) ++name;
339 	do
340 	{
341 		if( name[0] == std_merge_scanlines_func_list[i].name[0] )
342 			if( mystrncasecmp( name, std_merge_scanlines_func_list[i].name,
343 			                   std_merge_scanlines_func_list[i].name_len ) == 0 )
344 				return std_merge_scanlines_func_list[i].func ;
345 
346 	}while( std_merge_scanlines_func_list[++i].name != NULL );
347 
348 	return NULL ;
349 
350 }
351 
352 void
list_scanline_merging(FILE * stream,const char * format)353 list_scanline_merging(FILE* stream, const char *format)
354 {
355 	int i = 0 ;
356 	do
357 	{
358 		fprintf( stream, format,
359 			     std_merge_scanlines_func_list[i].name,
360 			     std_merge_scanlines_func_list[i].short_desc  );
361 	}while( std_merge_scanlines_func_list[++i].name != NULL );
362 }
363 
364 #define BLEND_SCANLINES_HEADER \
365 	register int i = -1, max_i = bottom->width ; \
366 	register CARD32 *ta = top->alpha, *tr = top->red, *tg = top->green, *tb = top->blue; \
367 	register CARD32 *ba = bottom->alpha, *br = bottom->red, *bg = bottom->green, *bb = bottom->blue; \
368 	if( offset < 0 ){ \
369 		offset = -offset ; \
370 		ta += offset ;	tr += offset ;	tg += offset ;	tb += offset ; \
371 		if( (int)top->width-offset < max_i )	max_i = (int)(top->width)-offset ; \
372 	}else{ \
373 		if( offset > 0 ){ \
374 			ba += offset ;	br += offset ;	bg += offset ;	bb += offset ; \
375 			max_i -= offset ; }	\
376 		if( (int)(top->width) < max_i )	max_i = top->width ; \
377 	}
378 
379 
380 
381 void
alphablend_scanlines(ASScanline * bottom,ASScanline * top,int offset)382 alphablend_scanlines( ASScanline *bottom, ASScanline *top, int offset )
383 {
384 	BLEND_SCANLINES_HEADER
385 	while( ++i < max_i )
386 	{
387 		int a = ta[i] ;
388 		int ca ;
389 /*fprintf( stderr, "%4.4x%4.4x%4.4x%4.4x+%4.4x%4.4x%4.4x%4.4x ", ba[i], br[i], bg[i], bb[i], ta[i], tr[i], tg[i], tb[i] );*/
390 		if( a >= 0x0000FF00 )
391 		{
392 			br[i] = tr[i] ;
393 			bg[i] = tg[i] ;
394 			bb[i] = tb[i] ;
395 			ba[i] = 0x0000FF00;
396 		}else if( a > 0x000000FF )
397 		{
398 			a = (a>>8) ;
399 			ca = 255-a;
400 #if 0 /*ndef HAVE_MMX*/
401 /* MMX implementaion of alpha-blending below turns out to be
402    30% slower then the original integer math implementation under it
403    I'm probably stupid or something.
404  */
405 			__m64	va  = _mm_set_pi16 (ca, a, ca, a);
406 			__m64	vd  = _mm_set_pi16 (br[i],tr[i],ba[i],ta[i]);
407 
408 			/* b=(b*ca + t*a)>>8 */
409 			vd = _mm_srli_pi16( vd, 8 );
410 			vd = _mm_madd_pi16( va, vd );
411 			ba[i] = _mm_cvtsi64_si32( vd );
412 			vd = _mm_srli_si64( vd, 32 );
413 			br[i] = _mm_cvtsi64_si32( vd );
414 
415 			vd = _mm_set_pi16 (bb[i],tb[i],bg[i],tg[i]);
416 			vd = _mm_srli_pi16( vd, 8 );
417 			vd = _mm_madd_pi16( va, vd );
418 			bg[i] = _mm_cvtsi64_si32( vd );
419 			vd = _mm_srli_si64( vd, 32 );
420 			bb[i] = _mm_cvtsi64_si32( vd );
421 			_mm_empty();
422 #else
423 			ba[i] = ((ba[i]*ca)>>8)+ta[i] ;
424 			br[i] = (br[i]*ca+tr[i]*a)>>8 ;
425 			bg[i] = (bg[i]*ca+tg[i]*a)>>8 ;
426 			bb[i] = (bb[i]*ca+tb[i]*a)>>8 ;
427 #endif
428 		}
429 	}
430 
431 /*	fputc( '\n', stderr );*/
432 }
433 
434 void    /* this one was first implemented on XImages by allanon :) - mode 131  */
allanon_scanlines(ASScanline * bottom,ASScanline * top,int offset)435 allanon_scanlines( ASScanline *bottom, ASScanline *top, int offset )
436 {
437 	BLEND_SCANLINES_HEADER
438 	while( ++i < max_i )
439 	{
440 		if( ta[i] != 0 )
441 		{
442 			br[i] = (br[i]+tr[i])>>1 ;
443 			bg[i] = (bg[i]+tg[i])>>1 ;
444 			bb[i] = (bb[i]+tb[i])>>1 ;
445 			ba[i] = (ba[i]+ta[i])>>1 ;
446 		}
447 	}
448 }
449 
450 void
tint_scanlines(ASScanline * bottom,ASScanline * top,int offset)451 tint_scanlines( ASScanline *bottom, ASScanline *top, int offset )
452 {
453 	BLEND_SCANLINES_HEADER
454 	while( ++i < max_i )
455 	{
456 		if( ta[i] != 0 )
457 		{
458 			br[i] = (br[i]*(tr[i]>>1))>>15 ;
459 			bg[i] = (bg[i]*(tg[i]>>1))>>15 ;
460 			bb[i] = (bb[i]*(tb[i]>>1))>>15 ;
461 		}
462 	}
463 }
464 
465 void    /* addition with saturation : */
add_scanlines(ASScanline * bottom,ASScanline * top,int offset)466 add_scanlines( ASScanline *bottom, ASScanline *top, int offset )
467 {
468 	BLEND_SCANLINES_HEADER
469 	while( ++i < max_i )
470 		if( ta[i] )
471 		{
472 			if( ta[i] > ba[i] )
473 				ba[i] = ta[i] ;
474 			br[i] = (br[i]+tr[i]) ;
475 			if( br[i] > 0x0000FFFF )
476 				br[i] = 0x0000FFFF ;
477 			bg[i] = (bg[i]+tg[i]) ;
478 			if( bg[i] > 0x0000FFFF )
479 				bg[i] = 0x0000FFFF ;
480 			bb[i] = (bb[i]+tb[i]) ;
481 			if( bb[i] > 0x0000FFFF )
482 				bb[i] = 0x0000FFFF ;
483 			ba[i] = (ba[i]+ta[i]) ;
484 			if( ba[i] > 0x0000FFFF )
485 				ba[i] = 0x0000FFFF ;
486 		}
487 }
488 
489 void    /* substruction with saturation : */
sub_scanlines(ASScanline * bottom,ASScanline * top,int offset)490 sub_scanlines( ASScanline *bottom, ASScanline *top, int offset )
491 {
492 	BLEND_SCANLINES_HEADER
493 	while( ++i < max_i )
494 		if( ta[i] )
495 		{
496 			int res ;
497 			if( ta[i] > ba[i] )
498 				ba[i] = ta[i] ;
499 			res = (int)br[i] - (int)tr[i] ;
500 			br[i] = res < 0 ? 0: res ;
501 			res = (int)bg[i] - (int)tg[i] ;
502 			bg[i] = res < 0 ? 0: res ;
503 			res = (int)bb[i] - (int)tb[i] ;
504 			bb[i] = res < 0 ? 0: res ;
505 		}
506 }
507 
508 void    /* absolute pixel value difference : */
diff_scanlines(ASScanline * bottom,ASScanline * top,int offset)509 diff_scanlines( ASScanline *bottom, ASScanline *top, int offset )
510 {
511 	BLEND_SCANLINES_HEADER
512 	while( ++i < max_i )
513 	{
514 		if( ta[i] )
515 		{
516 			int res = (int)br[i] - (int)tr[i] ;
517 			br[i] = res < 0 ? -res: res ;
518 			res = (int)bg[i] - (int)tg[i] ;
519 			bg[i] = res < 0 ? -res: res ;
520 			res = (int)bb[i] - (int)tb[i] ;
521 			bb[i] = res < 0 ? -res: res ;
522 
523 			if( ta[i] > ba[i] )
524 				ba[i] = ta[i] ;
525 		}
526 	}
527 }
528 
529 void    /* darkest of the two makes it in : */
darken_scanlines(ASScanline * bottom,ASScanline * top,int offset)530 darken_scanlines( ASScanline *bottom, ASScanline *top, int offset )
531 {
532 	BLEND_SCANLINES_HEADER
533 	while( ++i < max_i )
534 		if( ta[i] )
535 		{
536 			if( ta[i] < ba[i] )
537 				ba[i] = ta[i] ;
538 			if( tr[i] < br[i] )
539 				br[i] = tr[i];
540 			if( tg[i] < bg[i] )
541 				bg[i] = tg[i];
542 			if( tb[i] < bb[i] )
543 				bb[i] = tb[i];
544 		}
545 }
546 
547 void    /* lightest of the two makes it in : */
lighten_scanlines(ASScanline * bottom,ASScanline * top,int offset)548 lighten_scanlines( ASScanline *bottom, ASScanline *top, int offset )
549 {
550 	BLEND_SCANLINES_HEADER
551 	while( ++i < max_i )
552 		if( ta[i] )
553 		{
554 			if( ta[i] > ba[i] )
555 				ba[i] = ta[i] ;
556 			if( tr[i] > br[i] )
557 				br[i] = tr[i];
558 			if( tg[i] > bg[i] )
559 				bg[i] = tg[i];
560 			if( tb[i] > bb[i] )
561 				bb[i] = tb[i];
562 		}
563 }
564 
565 void    /* guess what this one does - I could not :) */
screen_scanlines(ASScanline * bottom,ASScanline * top,int offset)566 screen_scanlines( ASScanline *bottom, ASScanline *top, int offset )
567 {
568 	BLEND_SCANLINES_HEADER
569 #define DO_SCREEN_VALUE(b,t) \
570 			res1 = 0x0000FFFF - (int)b[i] ; res2 = 0x0000FFFF - (int)t[i] ;\
571 			res1 = 0x0000FFFF - ((res1*res2)>>16); b[i] = res1 < 0 ? 0 : res1
572 
573 	while( ++i < max_i )
574 		if( ta[i] )
575 		{
576 			int res1 ;
577 			int res2 ;
578 
579 			DO_SCREEN_VALUE(br,tr);
580 			DO_SCREEN_VALUE(bg,tg);
581 			DO_SCREEN_VALUE(bb,tb);
582 
583 			if( ta[i] > ba[i] )
584 				ba[i] = ta[i] ;
585 		}
586 }
587 
588 void    /* somehow overlays bottom with top : */
overlay_scanlines(ASScanline * bottom,ASScanline * top,int offset)589 overlay_scanlines( ASScanline *bottom, ASScanline *top, int offset )
590 {
591 	BLEND_SCANLINES_HEADER
592 #define DO_OVERLAY_VALUE(b,t) \
593 				tmp_screen = 0x0000FFFF - (((0x0000FFFF - (int)b[i]) * (0x0000FFFF - (int)t[i])) >> 16); \
594 				tmp_mult   = (b[i] * t[i]) >> 16; \
595 				res = (b[i] * tmp_screen + (0x0000FFFF - (int)b[i]) * tmp_mult) >> 16; \
596 				b[i] = res < 0 ? 0 : res
597 
598 	while( ++i < max_i )
599 		if( ta[i] )
600 		{
601 			int tmp_screen, tmp_mult, res ;
602 			DO_OVERLAY_VALUE(br,tr);
603 			DO_OVERLAY_VALUE(bg,tg);
604 			DO_OVERLAY_VALUE(bb,tb);
605 			if( ta[i] > ba[i] )
606 				ba[i] = ta[i] ;
607 		}
608 }
609 
610 void
hue_scanlines(ASScanline * bottom,ASScanline * top,int offset)611 hue_scanlines( ASScanline *bottom, ASScanline *top, int offset )
612 {
613 	BLEND_SCANLINES_HEADER
614 	while( ++i < max_i )
615 		if( ta[i] )
616 		{
617 			CARD32 hue = rgb2hue( tr[i], tg[i], tb[i]);
618 			if( hue > 0 )
619 			{
620 				CARD32 saturation = rgb2saturation( br[i], bg[i], bb[i]);
621 				CARD32 value = rgb2value( br[i], bg[i], bb[i]);;
622 
623 				hsv2rgb(hue, saturation, value, &br[i], &bg[i], &bb[i]);
624 			}
625 			if( ta[i] < ba[i] )
626 				ba[i] = ta[i] ;
627 		}
628 }
629 
630 void
saturate_scanlines(ASScanline * bottom,ASScanline * top,int offset)631 saturate_scanlines( ASScanline *bottom, ASScanline *top, int offset )
632 {
633 	BLEND_SCANLINES_HEADER
634 	while( ++i < max_i )
635 		if( ta[i] )
636 		{
637 			CARD32 saturation, value;
638 			CARD32 hue = rgb2hsv( br[i], bg[i], bb[i], &saturation, &value);
639 
640 			saturation = rgb2saturation( tr[i], tg[i], tb[i]);
641 			hsv2rgb(hue, saturation, value, &br[i], &bg[i], &bb[i]);
642 			if( ta[i] < ba[i] )
643 				ba[i] = ta[i] ;
644 		}
645 }
646 
647 void
value_scanlines(ASScanline * bottom,ASScanline * top,int offset)648 value_scanlines( ASScanline *bottom, ASScanline *top, int offset )
649 {
650 	BLEND_SCANLINES_HEADER
651 	while( ++i < max_i )
652 		if( ta[i] )
653 		{
654 			CARD32 saturation, value;
655 			CARD32 hue = rgb2hsv( br[i], bg[i], bb[i], &saturation, &value);
656 
657 			value = rgb2value( tr[i], tg[i], tb[i]);
658 			hsv2rgb(hue, saturation, value, &br[i], &bg[i], &bb[i]);
659 
660 			if( ta[i] < ba[i] )
661 				ba[i] = ta[i] ;
662 		}
663 }
664 
665 void
colorize_scanlines(ASScanline * bottom,ASScanline * top,int offset)666 colorize_scanlines( ASScanline *bottom, ASScanline *top, int offset )
667 {
668 	BLEND_SCANLINES_HEADER
669 
670 	while( ++i < max_i )
671 		if( ta[i] )
672 		{
673 #if 1
674 			CARD32 luminance, saturation ;
675 			CARD32 hue = rgb2hls( tr[i], tg[i], tb[i], &luminance, &saturation );
676 
677 			luminance = rgb2luminance( br[i], bg[i], bb[i]);
678 			hls2rgb(hue, luminance, saturation, &br[i], &bg[i], &bb[i]);
679 #else
680 			CARD32 h, l, s, r, g, b;
681 			h = rgb2hls( br[i], bg[i], bb[i], &l, &s );
682 			hls2rgb( h, l, s, &r, &g, &b );
683 			if( r > br[i]+10 || r < br[i] - 10 )
684 			{
685 				fprintf( stderr, "%X.%X.%X -> %X.%X.%X -> %X.%X.%X\n",  br[i], bg[i], bb[i], h, l, s, r, g, b );
686 				fprintf( stderr, "%d.%d.%d -> %d.%d.%d -> %d.%d.%d\n",  br[i], bg[i], bb[i], h, l, s, r, g, b );
687 			}
688 #endif
689 			if( ta[i] < ba[i] )
690 				ba[i] = ta[i] ;
691 		}
692 }
693 
694 void
dissipate_scanlines(ASScanline * bottom,ASScanline * top,int offset)695 dissipate_scanlines( ASScanline *bottom, ASScanline *top, int offset )
696 {
697 	static   CARD32 rnd32_seed = 345824357;
698 	BLEND_SCANLINES_HEADER
699 
700 #define MAX_MY_RND32		0x00ffffffff
701 #ifdef WORD64
702 #define MY_RND32() \
703 (rnd32_seed = ((1664525L*rnd32_seed)&MAX_MY_RND32)+1013904223L)
704 #else
705 #define MY_RND32() \
706 (rnd32_seed = (1664525L*rnd32_seed)+1013904223L)
707 #endif
708 
709 	/* add some randomization here  if (rand < alpha) - combine */
710 	while( ++i < max_i )
711 	{
712 		int a = ta[i] ;
713 		if( a > 0 && (int)MY_RND32() < (a<<15) )
714 		{
715 			ba[i] += a ;
716 			if( ba[i] > 0x0000FFFF )
717 				ba[i] = 0x0000FFFF ;
718 			a = (a>>8) ;
719 			br[i] = (br[i]*(255-a)+tr[i]*a)>>8 ;
720 			bg[i] = (bg[i]*(255-a)+tg[i]*a)>>8 ;
721 			bb[i] = (bb[i]*(255-a)+tb[i]*a)>>8 ;
722 		}
723 	}
724 }
725 
726 /*********************************************************************************/
727 /* The end !!!! 																 */
728 /*********************************************************************************/
729 
730