]> git.sesse.net Git - vlc/blobdiff - modules/gui/beos/DrawingTidbits.cpp
Attempt to port new BeOS features from the stable branch.
[vlc] / modules / gui / beos / DrawingTidbits.cpp
index f62db433425331ba1e4cef2f9c4a399e72745af8..8f0bd468a4a5aa4388c31ed47581ed87b22f558e 100644 (file)
@@ -2,9 +2,10 @@
  * DrawingTidbits.cpp
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: DrawingTidbits.cpp,v 1.1 2002/08/04 17:23:43 sam Exp $
+ * $Id: DrawingTidbits.cpp,v 1.2 2002/09/30 18:30:27 titer Exp $
  *
  * Authors: Tony Castley <tcastley@mail.powerup.com.au>
+ *          Stephan Aßmus <stippi@yellowbites.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
+#include <math.h>
+
 #include <Bitmap.h>
 #include <Debug.h>
 #include <Screen.h>
 
 #include "DrawingTidbits.h"
 
+// ShiftComponent
 inline uchar
 ShiftComponent(uchar component, float percent)
 {
@@ -38,6 +42,7 @@ ShiftComponent(uchar component, float percent)
                return (uchar)(255 - percent * (255 - component));
 }
 
+// ShiftColor
 rgb_color
 ShiftColor(rgb_color color, float percent)
 {
@@ -51,6 +56,7 @@ ShiftColor(rgb_color color, float percent)
        return result;
 }
 
+// CompareColors
 static bool
 CompareColors(const rgb_color a, const rgb_color b)
 {
@@ -60,18 +66,21 @@ CompareColors(const rgb_color a, const rgb_color b)
                && a.alpha == b.alpha;
 }
 
-bool 
+// ==
+bool
 operator==(const rgb_color &a, const rgb_color &b)
 {
        return CompareColors(a, b);
 }
 
-bool 
+// !=
+bool
 operator!=(const rgb_color &a, const rgb_color &b)
 {
        return !CompareColors(a, b);
 }
 
+// ReplaceColor
 void
 ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
 {
@@ -88,6 +97,7 @@ ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
                        bits[index] = toIndex;
 }
 
+// ReplaceTransparentColor
 void 
 ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
 {
@@ -103,3 +113,366 @@ ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
                        bits[index] = withIndex;
 }
 
+// ycrcb_to_rgb
+inline void
+ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
+                         uint8& r, uint8& g, uint8& b)
+{
+       r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
+       g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
+                                                               - 0.391 * ( cb - 128 ) ) );
+       b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
+}
+
+// this function will not produce visually pleasing results!
+// we'd have to convert to Lab colorspace, do the mixing
+// and convert back to RGB - in an ideal world...
+//
+// mix_colors
+inline void
+mix_colors( uint8 ra, uint8 ga, uint8 ba,
+                       uint8 rb, uint8 gb, uint8 bb,
+                       uint8& r, uint8& g, uint8& b, float mixLevel )
+{
+       float mixA = ( 1.0 - mixLevel );
+       float mixB = mixLevel;
+       r = (uint8)(mixA * ra + mixB * rb);
+       g = (uint8)(mixA * ga + mixB * gb);
+       b = (uint8)(mixA * ba + mixB * bb);
+}
+
+// the algorithm used is probably pretty slow, but it should be easy
+// to understand what's going on...
+//
+// scale_bitmap
+status_t
+scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
+{
+       status_t status = B_BAD_VALUE;
+       
+       if ( bitmap && bitmap->IsValid()
+                && ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
+       {
+               status = B_MISMATCHED_VALUES;
+               // we only support upscaling as of now
+               uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
+               uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
+               if ( fromWidth <= destWidth && fromHeight <= destHeight )
+               {
+                       status = B_OK;
+                       uint32 bpr = bitmap->BytesPerRow();
+                       if ( fromWidth < destWidth )
+                       {
+                               // scale horizontally
+                               uint8* src = (uint8*)bitmap->Bits();
+                               uint8* p = new uint8[fromWidth * 4];    // temp buffer
+                               for ( uint32 y = 0; y < fromHeight; y++ )
+                               {
+                                       // copy valid pixels into temp buffer
+                                       memcpy( p, src, fromWidth * 4 );
+                                       for ( uint32 x = 0; x < destWidth; x++ )
+                                       {
+                                               // mix colors of left and right pixels and write it back
+                                               // into the bitmap
+                                               float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
+                                               uint32 leftIndex = (uint32)floorf( xPos ) * 4;
+                                               uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
+                                               rgb_color left;
+                                               left.red = p[leftIndex + 2];
+                                               left.green = p[leftIndex + 1];
+                                               left.blue = p[leftIndex + 0];
+                                               rgb_color right;
+                                               right.red = p[rightIndex + 2];
+                                               right.green = p[rightIndex + 1];
+                                               right.blue = p[rightIndex + 0];
+                                               rgb_color mix;
+                                               mix_colors( left.red, left.green, left.blue,
+                                                                       right.red, right.green, right.blue,
+                                                                       mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
+                                               uint32 destIndex = x * 4;
+                                               src[destIndex + 2] = mix.red;
+                                               src[destIndex + 1] = mix.green;
+                                               src[destIndex + 0] = mix.blue;
+                                       }
+                                       src += bpr;
+                               }
+                               delete[] p;
+                       }
+                       if ( fromHeight < destHeight )
+                       {
+                               // scale vertically
+                               uint8* src = (uint8*)bitmap->Bits();
+                               uint8* p = new uint8[fromHeight * 3];   // temp buffer
+                               for ( uint32 x = 0; x < destWidth; x++ )
+                               {
+                                       // copy valid pixels into temp buffer
+                                       for ( uint32 y = 0; y < fromHeight; y++ )
+                                       {
+                                               uint32 destIndex = y * 3;
+                                               uint32 srcIndex = x * 4 + y * bpr;
+                                               p[destIndex + 0] = src[srcIndex + 0];
+                                               p[destIndex + 1] = src[srcIndex + 1];
+                                               p[destIndex + 2] = src[srcIndex + 2];
+                                       }
+                                       // do the scaling
+                                       for ( uint32 y = 0; y < destHeight; y++ )
+                                       {
+                                               // mix colors of upper and lower pixels and write it back
+                                               // into the bitmap
+                                               float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
+                                               uint32 upperIndex = (uint32)floorf( yPos ) * 3;
+                                               uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
+                                               rgb_color upper;
+                                               upper.red = p[upperIndex + 2];
+                                               upper.green = p[upperIndex + 1];
+                                               upper.blue = p[upperIndex + 0];
+                                               rgb_color lower;
+                                               lower.red = p[lowerIndex + 2];
+                                               lower.green = p[lowerIndex + 1];
+                                               lower.blue = p[lowerIndex + 0];
+                                               rgb_color mix;
+                                               mix_colors( upper.red, upper.green, upper.blue,
+                                                                       lower.red, lower.green, lower.blue,
+                                                                       mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
+                                               uint32 destIndex = x * 4 + y * bpr;
+                                               src[destIndex + 2] = mix.red;
+                                               src[destIndex + 1] = mix.green;
+                                               src[destIndex + 0] = mix.blue;
+                                       }
+                               }
+                               delete[] p;
+                       }
+               }
+       }
+       return status;
+}
+
+// convert_bitmap
+status_t
+convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
+{
+       status_t status = B_BAD_VALUE;
+       // see that we got valid bitmaps
+       if ( inBitmap && inBitmap->IsValid()
+                && outBitmap && outBitmap->IsValid() )
+       {
+               status = B_MISMATCHED_VALUES;
+               // see that bitmaps are compatible and that we support the conversion
+               if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
+                        && inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
+                        && ( outBitmap->ColorSpace() == B_RGB32
+                                 || outBitmap->ColorSpace() == B_RGBA32) )
+               {
+                       int32 width = inBitmap->Bounds().IntegerWidth() + 1;
+                       int32 height = inBitmap->Bounds().IntegerHeight() + 1;
+                       int32 srcBpr = inBitmap->BytesPerRow();
+                       int32 dstBpr = outBitmap->BytesPerRow();
+                       uint8* srcBits = (uint8*)inBitmap->Bits();
+                       uint8* dstBits = (uint8*)outBitmap->Bits();
+                       switch (inBitmap->ColorSpace())
+                       {
+                               case B_YCbCr422:
+                                       // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]
+                                       // Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
+                                       for ( int32 y = 0; y < height; y++ )
+                                       {
+                                               for ( int32 x = 0; x < width; x += 2 )
+                                               {
+                                                       int32 srcOffset = x * 2;
+                                                       int32 dstOffset = x * 4;
+                                                       ycbcr_to_rgb( srcBits[srcOffset + 0],
+                                                                                 srcBits[srcOffset + 1],
+                                                                                 srcBits[srcOffset + 3],
+                                                                                 dstBits[dstOffset + 2],
+                                                                                 dstBits[dstOffset + 1],
+                                                                                 dstBits[dstOffset + 0] );
+                                                       ycbcr_to_rgb( srcBits[srcOffset + 2],
+                                                                                 srcBits[srcOffset + 1],
+                                                                                 srcBits[srcOffset + 3],
+                                                                                 dstBits[dstOffset + 6],
+                                                                                 dstBits[dstOffset + 5],
+                                                                                 dstBits[dstOffset + 4] );
+                                                       // take care of alpha
+                                                       dstBits[x * 4 + 3] = 255;
+                                                       dstBits[x * 4 + 7] = 255;
+                                               }
+                                               srcBits += srcBpr;
+                                               dstBits += dstBpr;
+                                       }
+                                       status = B_OK;
+                                       break;
+                               case B_YCbCr420:
+                                       // Non-interlaced only!
+                                       // Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
+                                       // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
+                                       status = B_ERROR;
+                                       break;
+                               case B_YUV422:
+                                       // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0] 
+                                       // U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
+                                       status = B_ERROR;
+                                       break;
+                               case B_RGB32:
+                               case B_RGBA32:
+                                       memcpy( dstBits, srcBits, inBitmap->BitsLength() );
+                                       status = B_OK;
+                                       break;
+                               case B_RGB16:
+                                       // G[2:0],B[4:0]  R[4:0],G[5:3]
+                                       for ( int32 y = 0; y < height; y ++ )
+                                       {
+                                               for ( int32 x = 0; x < width; x++ )
+                                               {
+                                                       int32 srcOffset = x * 2;
+                                                       int32 dstOffset = x * 4;
+                                                       uint8 blue = srcBits[srcOffset + 0] & 0x1f;
+                                                       uint8 green = ( srcBits[srcOffset + 0] >> 5 )
+                                                                                 | ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
+                                                       uint8 red = srcBits[srcOffset + 1] & 0xf8;
+                                                       // homogeneously scale each component to 8 bit
+                                                       dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
+                                                       dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
+                                                       dstBits[dstOffset + 2] = red | (red >> 5);
+                                               }
+                                               srcBits += srcBpr;
+                                               dstBits += dstBpr;
+                                       }
+                                       status = B_OK;
+                                       break;
+                               default:
+//printf("unkown colorspace: %ld\n", inBitmap->ColorSpace());
+                                       status = B_MISMATCHED_VALUES;
+                                       break;
+                       }
+                       if ( status == B_OK )
+                       {
+                               if ( width < outBitmap->Bounds().IntegerWidth() + 1
+                                        || height < outBitmap->Bounds().IntegerHeight() + 1 )
+                               {
+                                       scale_bitmap( outBitmap, width, height );
+                               }
+                       }
+               }
+       }
+       return status;
+}
+
+// clip_float
+inline uint8
+clip_float(float value)
+{
+       if (value < 0)
+               value = 0;
+       if (value > 255)
+               value = 255;
+       return (uint8)value;
+}
+
+// dim_bitmap
+status_t
+dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
+{
+       status_t status = B_BAD_VALUE;
+       if (bitmap && bitmap->IsValid())
+       {
+               switch (bitmap->ColorSpace())
+               {
+                       case B_CMAP8:
+                       {
+                               BScreen screen(B_MAIN_SCREEN_ID);
+                               if (screen.IsValid())
+                               {
+                                       // iterate over each pixel, get the respective
+                                       // color from the screen object, find the distance
+                                       // to the "center" color and shorten the distance
+                                       // by "dimLevel"
+                                       int32 length = bitmap->BitsLength();
+                                       uint8* bits = (uint8*)bitmap->Bits();
+                                       for (int32 i = 0; i < length; i++)
+                                       {
+                                               // preserve transparent pixels
+                                               if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
+                                               {
+                                                       // get color for this index
+                                                       rgb_color c = screen.ColorForIndex(bits[i]);
+                                                       // red
+                                                       float dist = (c.red - center.red) * dimLevel;
+                                                       c.red = clip_float(center.red + dist);
+                                                       // green
+                                                       dist = (c.green - center.green) * dimLevel;
+                                                       c.green = clip_float(center.green + dist);
+                                                       // blue
+                                                       dist = (c.blue - center.blue) * dimLevel;
+                                                       c.blue = clip_float(center.blue + dist);
+                                                       // write correct index of the dimmed color
+                                                       // back into bitmap (and hope the match is close...)
+                                                       bits[i] = screen.IndexForColor(c);
+                                               }
+                                       }
+                                       status = B_OK;
+                               }
+                               break;
+                       }
+                       case B_RGB32:
+                       case B_RGBA32:
+                       {
+                               // iterate over each color component, find the distance
+                               // to the "center" color and shorten the distance
+                               // by "dimLevel"
+                               uint8* bits = (uint8*)bitmap->Bits();
+                               int32 bpr = bitmap->BytesPerRow();
+                               int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
+                               int32 lines = bitmap->Bounds().IntegerHeight() + 1;
+                               // iterate over color components
+                               for (int32 y = 0; y < lines; y++) {
+                                       for (int32 x = 0; x < pixels; x++) {
+                                               int32 offset = 4 * x; // four bytes per pixel
+                                               // blue
+                                               float dist = (bits[offset + 0] - center.blue) * dimLevel;
+                                               bits[offset + 0] = clip_float(center.blue + dist);
+                                               // green
+                                               dist = (bits[offset + 1] - center.green) * dimLevel;
+                                               bits[offset + 1] = clip_float(center.green + dist);
+                                               // red
+                                               dist = (bits[offset + 2] - center.red) * dimLevel;
+                                               bits[offset + 2] = clip_float(center.red + dist);
+                                               // ignore alpha channel
+                                       }
+                                       // next line
+                                       bits += bpr;
+                               }
+                               status = B_OK;
+                               break;
+                       }
+                       default:
+                               status = B_ERROR;
+                               break;
+               }
+       }
+       return status;
+}
+
+// dimmed_color_cmap8
+rgb_color
+dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
+{
+       BScreen screen(B_MAIN_SCREEN_ID);
+       if (screen.IsValid())
+       {
+               // red
+               float dist = (color.red - center.red) * dimLevel;
+               color.red = clip_float(center.red + dist);
+               // green
+               dist = (color.green - center.green) * dimLevel;
+               color.green = clip_float(center.green + dist);
+               // blue
+               dist = (color.blue - center.blue) * dimLevel;
+               color.blue = clip_float(center.blue + dist);
+               // get color index for dimmed color
+               int32 index = screen.IndexForColor(color);
+               // put color at index (closest match in palette
+               // to dimmed result) into returned color
+               color = screen.ColorForIndex(index);
+       }
+       return color;
+}