Added copyright lines for files I've edited this year.
[synfig.git] / synfig-core / trunk / src / synfig / color.cpp
index 101e883..1dcc314 100644 (file)
@@ -1,11 +1,12 @@
 /* === S Y N F I G ========================================================= */
-/*!    \file color.h
+/*!    \file color.cpp
 **     \brief Color Class
 **
-**     $Id: color.cpp,v 1.2 2005/01/23 04:03:21 darco Exp $
+**     $Id$
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007, 2008 Chris Moore
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -32,6 +33,9 @@
 #include <ETL/angle>
 #include "color.h"
 #include <cstdio>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
 
 #endif
 
@@ -51,6 +55,77 @@ using namespace std;
 
 
 
+ColorReal
+Color::hex2real(String s)
+{
+       std::istringstream i(s);
+       int n;
+       i.fill('0');
+       if (!(i >> hex >> n))
+               throw String("bad conversion from hex string \"") + s + String("\"");
+       return n / 255.0f;
+}
+
+const String
+Color::real2hex(ColorReal c)
+{
+       std::ostringstream o;
+       o.width(2);
+       o.fill('0');
+       if (c<0) c = 0;
+       if (c>1) c = 1;
+       o << hex << int(c*255.0f);
+       return o.str();
+}
+
+void
+Color::set_hex(String& str)
+{
+       value_type r, g, b;
+       String hex;
+
+       // use just the hex characters
+       for (String::const_iterator iter = str.begin(); iter != str.end(); iter++)
+               if (isxdigit(*iter))
+                       hex.push_back(*iter);
+
+       try
+       {
+               if (hex.size() == 1)
+               {
+                       r = hex2real(hex.substr(0,1)+hex.substr(0,1));
+                       r_ = g_ = b_ = r;
+               }
+               else if (hex.size() == 3)
+               {
+                       r = hex2real(hex.substr(0,1)+hex.substr(0,1));
+                       g = hex2real(hex.substr(1,1)+hex.substr(1,1));
+                       b = hex2real(hex.substr(2,1)+hex.substr(2,1));
+                       r_ = r; g_ = g; b_ = b;
+               }
+               else if (hex.size() == 6)
+               {
+                       r = hex2real(hex.substr(0,2));
+                       g = hex2real(hex.substr(2,2));
+                       b = hex2real(hex.substr(4,2));
+                       r_ = r; g_ = g; b_ = b;
+               }
+       }
+       catch (string s)
+       {
+               printf("caught <%s>\n", s.c_str());
+               return;
+       }
+}
+
+const String
+Color::get_string(void)const
+{
+       std::ostringstream o;
+       o << std::fixed << std::setprecision(3) << "#" << get_hex() << " : " << std::setw(6) << a_;
+       return String(o.str().c_str());
+}
+
 #if 0
 Color&
 Color::rotate_uv(const Angle& theta)const
@@ -66,7 +141,7 @@ Color::rotate_uv(const Angle& theta)const
        const float
                u(get_u()),
                v(get_v());
-       
+
        return set_uv(b*u-a*v,a*u+b*v);
        //return YUV(get_y(),b*u-a*v,a*u+b*v,get_a());
 //*/
@@ -77,7 +152,7 @@ Color
 Color::clamped_negative()const
 {
        Color ret=*this;
-               
+
        if(ret.a_==0)
                return alpha();
 
@@ -162,13 +237,13 @@ blendfunc_COMPOSITE(Color &src,Color &dest,float amount)
 
        // if a_arc==0.0
        //if(fabsf(a_src)<COLOR_EPSILON) return dest;
-       
+
        // Scale the source and destination by their alpha values
        src*=a_src;
        dest*=a_dest;
-       
+
        dest=src + dest*(1.0f-a_src);
-       
+
        a_dest=a_src + a_dest*(1.0f-a_src);
 
        // if a_dest!=0.0
@@ -195,9 +270,9 @@ blendfunc_STRAIGHT(Color &src,Color &bg,float amount)
        //if(fabsf(amount-1.0f)<COLOR_EPSILON)return src;
 
        Color out;
-       
+
        float a_out((src.get_a()-bg.get_a())*amount+bg.get_a());
-       
+
        // if a_out!=0.0
        if(fabsf(a_out)>COLOR_EPSILON)
 //     if(a_out>COLOR_EPSILON || a_out<-COLOR_EPSILON)
@@ -230,7 +305,7 @@ static Color
 blendfunc_BRIGHTEN(Color &a,Color &b,float amount)
 {
        const float alpha(a.get_a()*amount);
-       
+
        if(b.get_r()<a.get_r()*alpha)
                b.set_r(a.get_r()*alpha);
 
@@ -239,7 +314,7 @@ blendfunc_BRIGHTEN(Color &a,Color &b,float amount)
 
        if(b.get_b()<a.get_b()*alpha)
                b.set_b(a.get_b()*alpha);
-       
+
        return b;
 }
 
@@ -247,7 +322,7 @@ static Color
 blendfunc_DARKEN(Color &a,Color &b,float amount)
 {
        const float alpha(a.get_a()*amount);
-       
+
        if(b.get_r()>(a.get_r()-1.0f)*alpha+1.0f)
                b.set_r((a.get_r()-1.0f)*alpha+1.0f);
 
@@ -257,7 +332,7 @@ blendfunc_DARKEN(Color &a,Color &b,float amount)
        if(b.get_b()>(a.get_b()-1.0f)*alpha+1.0f)
                b.set_b((a.get_b()-1.0f)*alpha+1.0f);
 
-       
+
        return b;
 }
 
@@ -316,9 +391,9 @@ blendfunc_DIVIDE(Color &a,Color &b,float amount)
 
        // We add COLOR_EPSILON in order to avoid a divide-by-zero condition.
        // This causes DIVIDE to bias toward positive values, but the effect is
-       // really neglegable. There is a reason why we use COLOR_EPSILON--we
-       // want the change to be imperceptable.
-       
+       // really negligible. There is a reason why we use COLOR_EPSILON--we
+       // want the change to be imperceptible.
+
        b.set_r(((b.get_r()/(a.get_r()+COLOR_EPSILON))-b.get_r())*(amount)+b.get_r());
        b.set_g(((b.get_g()/(a.get_g()+COLOR_EPSILON))-b.get_g())*(amount)+b.get_g());
        b.set_b(((b.get_b()/(a.get_b()+COLOR_EPSILON))-b.get_b())*(amount)+b.get_b());
@@ -331,7 +406,7 @@ blendfunc_COLOR(Color &a,Color &b,float amount)
 {
        Color temp(b);
        temp.set_uv(a.get_u(),a.get_v());
-       return (temp-b)*amount*a.get_a()+b;                     
+       return (temp-b)*amount*a.get_a()+b;
 }
 
 static Color
@@ -361,7 +436,7 @@ blendfunc_LUMINANCE(Color &a,Color &b,float amount)
 static Color
 blendfunc_BEHIND(Color &a,Color &b,float amount)
 {
-       if(a.get_a()==0)a.set_a(COLOR_EPSILON);         //!< \hack
+       if(a.get_a()==0)a.set_a(COLOR_EPSILON);         //!< \todo this is a hack
        a.set_a(a.get_a()*amount);
        return blendfunc_COMPOSITE(b,a,1.0);
 }
@@ -369,7 +444,9 @@ blendfunc_BEHIND(Color &a,Color &b,float amount)
 static Color
 blendfunc_ALPHA_BRIGHTEN(Color &a,Color &b,float amount)
 {
-       if(a.get_a()<b.get_a()*amount)
+       // \todo can this be right, multiplying amount by *b*'s alpha?
+       // compare with blendfunc_BRIGHTEN where it is multiplied by *a*'s
+       if(a.get_a() < b.get_a()*amount)
                return a.set_a(a.get_a()*amount);
        return b;
 }
@@ -377,7 +454,7 @@ blendfunc_ALPHA_BRIGHTEN(Color &a,Color &b,float amount)
 static Color
 blendfunc_ALPHA_DARKEN(Color &a,Color &b,float amount)
 {
-       if(a.get_a()*amount>b.get_a())
+       if(a.get_a()*amount > b.get_a())
                return a.set_a(a.get_a()*amount);
        return b;
 }
@@ -390,13 +467,13 @@ blendfunc_SCREEN(Color &a,Color &b,float amount)
        a.set_r(1.0-(1.0f-a.get_r())*(1.0f-b.get_r()));
        a.set_g(1.0-(1.0f-a.get_g())*(1.0f-b.get_g()));
        a.set_b(1.0-(1.0f-a.get_b())*(1.0f-b.get_b()));
-       
+
        return blendfunc_ONTO(a,b,amount);
 }
 
 static Color
 blendfunc_OVERLAY(Color &a,Color &b,float amount)
-{      
+{
        if(amount<0) a=~a, amount=-amount;
 
        Color rm;
@@ -410,7 +487,7 @@ blendfunc_OVERLAY(Color &a,Color &b,float amount)
        rs.set_b(1.0-(1.0f-a.get_b())*(1.0f-b.get_b()));
 
        Color& ret(a);
-       
+
        ret.set_r(a.get_r()*rs.get_r() + (1.0-a.get_r())*rm.get_r());
        ret.set_g(a.get_g()*rs.get_g() + (1.0-a.get_g())*rm.get_g());
        ret.set_b(a.get_b()*rs.get_b() + (1.0-a.get_b())*rm.get_b());
@@ -467,7 +544,7 @@ Color::blend(Color a, Color b,float amount, Color::BlendMethod type)
 #endif
        }
 #endif
-       
+
 /*
        if(!a.is_valid()&&b.is_valid())
                return b;
@@ -484,39 +561,39 @@ Color::blend(Color a, Color b,float amount, Color::BlendMethod type)
 #endif
        }
 */
-       
+
        // No matter what blend method is being used,
        // if the amount is equal to zero, then only B
        // will shine through
        if(fabsf(amount)<=COLOR_EPSILON)return b;
-       
+
        assert(type<BLEND_END);
-       
+
        const static blendfunc vtable[BLEND_END]=
        {
-               blendfunc_COMPOSITE, 
+               blendfunc_COMPOSITE,    // 0
                blendfunc_STRAIGHT,
                blendfunc_BRIGHTEN,
                blendfunc_DARKEN,
                blendfunc_ADD,
-               blendfunc_SUBTRACT,
+               blendfunc_SUBTRACT,             // 5
                blendfunc_MULTIPLY,
                blendfunc_DIVIDE,
                blendfunc_COLOR,
                blendfunc_HUE,
-               blendfunc_SATURATION,
+               blendfunc_SATURATION,   // 10
                blendfunc_LUMINANCE,
                blendfunc_BEHIND,
                blendfunc_ONTO,
                blendfunc_ALPHA_BRIGHTEN,
-               blendfunc_ALPHA_DARKEN,
+               blendfunc_ALPHA_DARKEN, // 15
                blendfunc_SCREEN,
                blendfunc_HARD_LIGHT,
                blendfunc_DIFFERENCE,
                blendfunc_ALPHA_OVER,
-               blendfunc_OVERLAY,
+               blendfunc_OVERLAY,              // 20
                blendfunc_STRAIGHT_ONTO,
        };
-       
+
        return vtable[type](a,b,amount);
 }