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