]> git.sesse.net Git - vlc/blob - modules/gui/beos/DrawingTidbits.cpp
Support for UDP-Lite (with full checksum coverage only atm)
[vlc] / modules / gui / beos / DrawingTidbits.cpp
1 /*****************************************************************************
2  * DrawingTidbits.cpp
3  *****************************************************************************
4  * Copyright (C) 2001 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Tony Castley <tcastley@mail.powerup.com.au>
8  *          Stephan Aßmus <stippi@yellowbites.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include <math.h>
26
27 #include <Bitmap.h>
28 #include <Debug.h>
29 #include <Screen.h>
30
31 #include "DrawingTidbits.h"
32
33 // ShiftComponent
34 inline uchar
35 ShiftComponent(uchar component, float percent)
36 {
37     // change the color by <percent>, make sure we aren't rounding
38     // off significant bits
39     if (percent >= 1)
40         return (uchar)(component * (2 - percent));
41     else
42         return (uchar)(255 - percent * (255 - component));
43 }
44
45 // ShiftColor
46 rgb_color
47 ShiftColor(rgb_color color, float percent)
48 {
49         rgb_color result = {
50                 ShiftComponent(color.red, percent),
51                 ShiftComponent(color.green, percent),
52                 ShiftComponent(color.blue, percent),
53                 0
54         };
55         
56         return result;
57 }
58
59 // CompareColors
60 static bool
61 CompareColors(const rgb_color a, const rgb_color b)
62 {
63         return a.red == b.red
64                 && a.green == b.green
65                 && a.blue == b.blue
66                 && a.alpha == b.alpha;
67 }
68
69 // ==
70 bool
71 operator==(const rgb_color &a, const rgb_color &b)
72 {
73         return CompareColors(a, b);
74 }
75
76 // !=
77 bool
78 operator!=(const rgb_color &a, const rgb_color &b)
79 {
80         return !CompareColors(a, b);
81 }
82
83 // ReplaceColor
84 void
85 ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
86 {
87         ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
88         
89         BScreen screen(B_MAIN_SCREEN_ID);
90         uint32 fromIndex = screen.IndexForColor(from);
91         uint32 toIndex = screen.IndexForColor(to); 
92         
93         uchar *bits = (uchar *)bitmap->Bits();
94         int32 bitsLength = bitmap->BitsLength();        
95         for (int32 index = 0; index < bitsLength; index++) 
96                 if (bits[index] == fromIndex)
97                         bits[index] = toIndex;
98 }
99
100 // ReplaceTransparentColor
101 void 
102 ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
103 {
104         ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
105         
106         BScreen screen(B_MAIN_SCREEN_ID);
107         uint32 withIndex = screen.IndexForColor(with); 
108         
109         uchar *bits = (uchar *)bitmap->Bits();
110         int32 bitsLength = bitmap->BitsLength();        
111         for (int32 index = 0; index < bitsLength; index++) 
112                 if (bits[index] == B_TRANSPARENT_8_BIT)
113                         bits[index] = withIndex;
114 }
115
116 // ycrcb_to_rgb
117 inline void
118 ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
119                           uint8& r, uint8& g, uint8& b)
120 {
121         r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
122         g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
123                                                                 - 0.391 * ( cb - 128 ) ) );
124         b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
125 }
126
127 // this function will not produce visually pleasing results!
128 // we'd have to convert to Lab colorspace, do the mixing
129 // and convert back to RGB - in an ideal world...
130 //
131 // mix_colors
132 inline void
133 mix_colors( uint8 ra, uint8 ga, uint8 ba,
134                         uint8 rb, uint8 gb, uint8 bb,
135                         uint8& r, uint8& g, uint8& b, float mixLevel )
136 {
137         float mixA = ( 1.0 - mixLevel );
138         float mixB = mixLevel;
139         r = (uint8)(mixA * ra + mixB * rb);
140         g = (uint8)(mixA * ga + mixB * gb);
141         b = (uint8)(mixA * ba + mixB * bb);
142 }
143
144 // the algorithm used is probably pretty slow, but it should be easy
145 // to understand what's going on...
146 //
147 // scale_bitmap
148 status_t
149 scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
150 {
151         status_t status = B_BAD_VALUE;
152         
153         if ( bitmap && bitmap->IsValid()
154                  && ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
155         {
156                 status = B_MISMATCHED_VALUES;
157                 // we only support upscaling as of now
158                 uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
159                 uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
160                 if ( fromWidth <= destWidth && fromHeight <= destHeight )
161                 {
162                         status = B_OK;
163                         uint32 bpr = bitmap->BytesPerRow();
164                         if ( fromWidth < destWidth )
165                         {
166                                 // scale horizontally
167                                 uint8* src = (uint8*)bitmap->Bits();
168                                 uint8* p = new uint8[fromWidth * 4];    // temp buffer
169                                 for ( uint32 y = 0; y < fromHeight; y++ )
170                                 {
171                                         // copy valid pixels into temp buffer
172                                         memcpy( p, src, fromWidth * 4 );
173                                         for ( uint32 x = 0; x < destWidth; x++ )
174                                         {
175                                                 // mix colors of left and right pixels and write it back
176                                                 // into the bitmap
177                                                 float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
178                                                 uint32 leftIndex = (uint32)floorf( xPos ) * 4;
179                                                 uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
180                                                 rgb_color left;
181                                                 left.red = p[leftIndex + 2];
182                                                 left.green = p[leftIndex + 1];
183                                                 left.blue = p[leftIndex + 0];
184                                                 rgb_color right;
185                                                 right.red = p[rightIndex + 2];
186                                                 right.green = p[rightIndex + 1];
187                                                 right.blue = p[rightIndex + 0];
188                                                 rgb_color mix;
189                                                 mix_colors( left.red, left.green, left.blue,
190                                                                         right.red, right.green, right.blue,
191                                                                         mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
192                                                 uint32 destIndex = x * 4;
193                                                 src[destIndex + 2] = mix.red;
194                                                 src[destIndex + 1] = mix.green;
195                                                 src[destIndex + 0] = mix.blue;
196                                         }
197                                         src += bpr;
198                                 }
199                                 delete[] p;
200                         }
201                         if ( fromHeight < destHeight )
202                         {
203                                 // scale vertically
204                                 uint8* src = (uint8*)bitmap->Bits();
205                                 uint8* p = new uint8[fromHeight * 3];   // temp buffer
206                                 for ( uint32 x = 0; x < destWidth; x++ )
207                                 {
208                                         // copy valid pixels into temp buffer
209                                         for ( uint32 y = 0; y < fromHeight; y++ )
210                                         {
211                                                 uint32 destIndex = y * 3;
212                                                 uint32 srcIndex = x * 4 + y * bpr;
213                                                 p[destIndex + 0] = src[srcIndex + 0];
214                                                 p[destIndex + 1] = src[srcIndex + 1];
215                                                 p[destIndex + 2] = src[srcIndex + 2];
216                                         }
217                                         // do the scaling
218                                         for ( uint32 y = 0; y < destHeight; y++ )
219                                         {
220                                                 // mix colors of upper and lower pixels and write it back
221                                                 // into the bitmap
222                                                 float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
223                                                 uint32 upperIndex = (uint32)floorf( yPos ) * 3;
224                                                 uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
225                                                 rgb_color upper;
226                                                 upper.red = p[upperIndex + 2];
227                                                 upper.green = p[upperIndex + 1];
228                                                 upper.blue = p[upperIndex + 0];
229                                                 rgb_color lower;
230                                                 lower.red = p[lowerIndex + 2];
231                                                 lower.green = p[lowerIndex + 1];
232                                                 lower.blue = p[lowerIndex + 0];
233                                                 rgb_color mix;
234                                                 mix_colors( upper.red, upper.green, upper.blue,
235                                                                         lower.red, lower.green, lower.blue,
236                                                                         mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
237                                                 uint32 destIndex = x * 4 + y * bpr;
238                                                 src[destIndex + 2] = mix.red;
239                                                 src[destIndex + 1] = mix.green;
240                                                 src[destIndex + 0] = mix.blue;
241                                         }
242                                 }
243                                 delete[] p;
244                         }
245                 }
246         }
247         return status;
248 }
249
250 // convert_bitmap
251 status_t
252 convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
253 {
254         status_t status = B_BAD_VALUE;
255         // see that we got valid bitmaps
256         if ( inBitmap && inBitmap->IsValid()
257                  && outBitmap && outBitmap->IsValid() )
258         {
259                 status = B_MISMATCHED_VALUES;
260                 // see that bitmaps are compatible and that we support the conversion
261                 if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
262                          && inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
263                          && ( outBitmap->ColorSpace() == B_RGB32
264                                   || outBitmap->ColorSpace() == B_RGBA32) )
265                 {
266                         int32 width = inBitmap->Bounds().IntegerWidth() + 1;
267                         int32 height = inBitmap->Bounds().IntegerHeight() + 1;
268                         int32 srcBpr = inBitmap->BytesPerRow();
269                         int32 dstBpr = outBitmap->BytesPerRow();
270                         uint8* srcBits = (uint8*)inBitmap->Bits();
271                         uint8* dstBits = (uint8*)outBitmap->Bits();
272                         switch (inBitmap->ColorSpace())
273                         {
274                                 case B_YCbCr422:
275                                         // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]
276                                         // Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
277                                         for ( int32 y = 0; y < height; y++ )
278                                         {
279                                                 for ( int32 x = 0; x < width; x += 2 )
280                                                 {
281                                                         int32 srcOffset = x * 2;
282                                                         int32 dstOffset = x * 4;
283                                                         ycbcr_to_rgb( srcBits[srcOffset + 0],
284                                                                                   srcBits[srcOffset + 1],
285                                                                                   srcBits[srcOffset + 3],
286                                                                                   dstBits[dstOffset + 2],
287                                                                                   dstBits[dstOffset + 1],
288                                                                                   dstBits[dstOffset + 0] );
289                                                         ycbcr_to_rgb( srcBits[srcOffset + 2],
290                                                                                   srcBits[srcOffset + 1],
291                                                                                   srcBits[srcOffset + 3],
292                                                                                   dstBits[dstOffset + 6],
293                                                                                   dstBits[dstOffset + 5],
294                                                                                   dstBits[dstOffset + 4] );
295                                                         // take care of alpha
296                                                         dstBits[x * 4 + 3] = 255;
297                                                         dstBits[x * 4 + 7] = 255;
298                                                 }
299                                                 srcBits += srcBpr;
300                                                 dstBits += dstBpr;
301                                         }
302                                         status = B_OK;
303                                         break;
304                                 case B_YCbCr420:
305                                         // Non-interlaced only!
306                                         // Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
307                                         // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
308                                         status = B_ERROR;
309                                         break;
310                                 case B_YUV422:
311                                         // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0] 
312                                         // U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
313                                         status = B_ERROR;
314                                         break;
315                                 case B_RGB32:
316                                 case B_RGBA32:
317                                         memcpy( dstBits, srcBits, inBitmap->BitsLength() );
318                                         status = B_OK;
319                                         break;
320                                 case B_RGB16:
321                                         // G[2:0],B[4:0]  R[4:0],G[5:3]
322                                         for ( int32 y = 0; y < height; y ++ )
323                                         {
324                                                 for ( int32 x = 0; x < width; x++ )
325                                                 {
326                                                         int32 srcOffset = x * 2;
327                                                         int32 dstOffset = x * 4;
328                                                         uint8 blue = srcBits[srcOffset + 0] & 0x1f;
329                                                         uint8 green = ( srcBits[srcOffset + 0] >> 5 )
330                                                                                   | ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
331                                                         uint8 red = srcBits[srcOffset + 1] & 0xf8;
332                                                         // homogeneously scale each component to 8 bit
333                                                         dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
334                                                         dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
335                                                         dstBits[dstOffset + 2] = red | (red >> 5);
336                                                 }
337                                                 srcBits += srcBpr;
338                                                 dstBits += dstBpr;
339                                         }
340                                         status = B_OK;
341                                         break;
342                                 default:
343                                         status = B_MISMATCHED_VALUES;
344                                         break;
345                         }
346                         if ( status == B_OK )
347                         {
348                                 if ( width < outBitmap->Bounds().IntegerWidth() + 1
349                                          || height < outBitmap->Bounds().IntegerHeight() + 1 )
350                                 {
351                                         scale_bitmap( outBitmap, width, height );
352                                 }
353                         }
354                 }
355         }
356         return status;
357 }
358
359 // clip_float
360 inline uint8
361 clip_float(float value)
362 {
363         if (value < 0)
364                 value = 0;
365         if (value > 255)
366                 value = 255;
367         return (uint8)value;
368 }
369
370 // dim_bitmap
371 status_t
372 dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
373 {
374         status_t status = B_BAD_VALUE;
375         if (bitmap && bitmap->IsValid())
376         {
377                 switch (bitmap->ColorSpace())
378                 {
379                         case B_CMAP8:
380                         {
381                                 BScreen screen(B_MAIN_SCREEN_ID);
382                                 if (screen.IsValid())
383                                 {
384                                         // iterate over each pixel, get the respective
385                                         // color from the screen object, find the distance
386                                         // to the "center" color and shorten the distance
387                                         // by "dimLevel"
388                                         int32 length = bitmap->BitsLength();
389                                         uint8* bits = (uint8*)bitmap->Bits();
390                                         for (int32 i = 0; i < length; i++)
391                                         {
392                                                 // preserve transparent pixels
393                                                 if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
394                                                 {
395                                                         // get color for this index
396                                                         rgb_color c = screen.ColorForIndex(bits[i]);
397                                                         // red
398                                                         float dist = (c.red - center.red) * dimLevel;
399                                                         c.red = clip_float(center.red + dist);
400                                                         // green
401                                                         dist = (c.green - center.green) * dimLevel;
402                                                         c.green = clip_float(center.green + dist);
403                                                         // blue
404                                                         dist = (c.blue - center.blue) * dimLevel;
405                                                         c.blue = clip_float(center.blue + dist);
406                                                         // write correct index of the dimmed color
407                                                         // back into bitmap (and hope the match is close...)
408                                                         bits[i] = screen.IndexForColor(c);
409                                                 }
410                                         }
411                                         status = B_OK;
412                                 }
413                                 break;
414                         }
415                         case B_RGB32:
416                         case B_RGBA32:
417                         {
418                                 // iterate over each color component, find the distance
419                                 // to the "center" color and shorten the distance
420                                 // by "dimLevel"
421                                 uint8* bits = (uint8*)bitmap->Bits();
422                                 int32 bpr = bitmap->BytesPerRow();
423                                 int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
424                                 int32 lines = bitmap->Bounds().IntegerHeight() + 1;
425                                 // iterate over color components
426                                 for (int32 y = 0; y < lines; y++) {
427                                         for (int32 x = 0; x < pixels; x++) {
428                                                 int32 offset = 4 * x; // four bytes per pixel
429                                                 // blue
430                                                 float dist = (bits[offset + 0] - center.blue) * dimLevel;
431                                                 bits[offset + 0] = clip_float(center.blue + dist);
432                                                 // green
433                                                 dist = (bits[offset + 1] - center.green) * dimLevel;
434                                                 bits[offset + 1] = clip_float(center.green + dist);
435                                                 // red
436                                                 dist = (bits[offset + 2] - center.red) * dimLevel;
437                                                 bits[offset + 2] = clip_float(center.red + dist);
438                                                 // ignore alpha channel
439                                         }
440                                         // next line
441                                         bits += bpr;
442                                 }
443                                 status = B_OK;
444                                 break;
445                         }
446                         default:
447                                 status = B_ERROR;
448                                 break;
449                 }
450         }
451         return status;
452 }
453
454 // dimmed_color_cmap8
455 rgb_color
456 dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
457 {
458         BScreen screen(B_MAIN_SCREEN_ID);
459         if (screen.IsValid())
460         {
461                 // red
462                 float dist = (color.red - center.red) * dimLevel;
463                 color.red = clip_float(center.red + dist);
464                 // green
465                 dist = (color.green - center.green) * dimLevel;
466                 color.green = clip_float(center.green + dist);
467                 // blue
468                 dist = (color.blue - center.blue) * dimLevel;
469                 color.blue = clip_float(center.blue + dist);
470                 // get color index for dimmed color
471                 int32 index = screen.IndexForColor(color);
472                 // put color at index (closest match in palette
473                 // to dimmed result) into returned color
474                 color = screen.ColorForIndex(index);
475         }
476         return color;
477 }