// // Computergraphik II // Prof. Dr. Juergen Doellner // Wintersemester 2001/2002 // // Rahmenprogramm fuer Aufgabenzettel 3 // // Autoren: Florian Kirsch (kirsch@hpi.uni-potsdam.de) // Marc Nienhaus (nienhaus@hpi.uni-potsdam.de) // Juergen Doellner (doellner@hpi.uni-potsdam.de) // #include "color.h" #include #include template static inline const T& Min(const T& a, const T& b) { return((a < b) ? a : b); } template static inline const T& Max(const T& a, const T& b) { return((a > b) ? a : b); } inline double clamp(double v) { return v>1 ? 1.0 : (v<0 ? 0 : v); } Color::Color(double grey) { rgba_[0] = rgba_[1] = rgba_[2] = grey; rgba_[3] = 1.0; } Color::Color(double r, double g, double b, double a) { rgba_[0] = r; rgba_[1] = g; rgba_[2] = b; rgba_[3] = a; } double Color::operator[](int i) const { assert(i>=0 && i<=3); return rgba_[i]; } double& Color::operator[](int i) { assert(i>=0 && i<=3); return rgba_[i]; } bool Color::operator==(const Color& mc) const { return rgba_[0]==mc.rgba_[0] && rgba_[1]==mc.rgba_[1] && rgba_[2]==mc.rgba_[2] && rgba_[3]==mc.rgba_[3]; } bool Color::operator!=(const Color& mc) const { return rgba_[0]!=mc.rgba_[0] || rgba_[1]!=mc.rgba_[1] || rgba_[2]!=mc.rgba_[2] || rgba_[3]!=mc.rgba_[3]; } Color Color::operator+(const Color& mc) const { double r = clamp(rgba_[0]+mc.rgba_[0]); double g = clamp(rgba_[1]+mc.rgba_[1]); double b = clamp(rgba_[2]+mc.rgba_[2]); double a = rgba_[3]; return Color(r,g,b,a); } Color Color::operator-(const Color& mc) const { double r = clamp(rgba_[0]-mc.rgba_[0]); double g = clamp(rgba_[1]-mc.rgba_[1]); double b = clamp(rgba_[2]-mc.rgba_[2]); double a = rgba_[3]; return Color(r,g,b,a); } Color Color::operator*(double d) const { double r = clamp(rgba_[0]*d); double g = clamp(rgba_[1]*d); double b = clamp(rgba_[2]*d); double a = rgba_[3]; return Color(r,g,b,a); } // // RGB - HSV // Color Color::hsv(double h, double s, double v, double alpha) { // normalize hue angle while (h< 0.0) h += 360.0; while (h>=360.0) h -= 360.0; assert(h>=-360.0 && h<=360.0); assert(v>=0.0 && v<=1.0); assert(s>=0.0 && s<=1.0); double R, G, B; if (s==0.0) { // color on black-white center line // achromatic color! R = v; G = v; B = v; } else { // chromatic color if (h==360.0) h = 0.0; if (h<0.0) h+=360.0; h = h/60.0; int i = (int)h; double f = h - i; double p = v*(1.0-s); double q = v*(1.0-(s*f)); double t = v*(1.0-(s*(1.0-f))); switch(i) { case 0: R = v; G = t; B = p; break; case 1: R = q; G = v; B = p; break; case 2: R = p; G = v; B = t; break; case 3: R = p; G = q; B = v; break; case 4: R = t; G = p; B = v; break; case 5: R = v; G = p; B = q; break; default: ; } } return Color(R,G,B,alpha); } double Color::value() const { return Max(rgba_[0], Max(rgba_[1], rgba_[2])); } double Color::saturation() const { double v = Max(rgba_[0], Max(rgba_[1], rgba_[2])); if(v!=0.0) { double m = Min(rgba_[0], Min(rgba_[1], rgba_[2])); return (v-m)/v; } else { return 0.0; } } double Color::hue() const { double s = saturation(); if(s==0.0) return 0.0; // hue is undefined double mmax = Max(rgba_[0], Max(rgba_[1], rgba_[2])); double mmin = Min(rgba_[0], Min(rgba_[1], rgba_[2])); double delta = mmax - mmin; double h; if(rgba_[0]==mmax) h = 0.0 + (rgba_[1]-rgba_[2])/delta; else if(rgba_[1]==mmax) h = 2.0 + (rgba_[2]-rgba_[0])/delta; else h = 4.0 + (rgba_[0]-rgba_[1])/delta; h = h * 60.0; if(h<0.0) h += 360.0; return h; } // interpolate two colors in RGBA space Color Color::InterpolateRGB(const Color& from, const Color& to, double dPercentage) { return Color(from[0]*(1-dPercentage) + to[0]*dPercentage, // red from[1]*(1-dPercentage) + to[1]*dPercentage, // green from[2]*(1-dPercentage) + to[2]*dPercentage, // blue from[3]*(1-dPercentage) + to[3]*dPercentage); // alpha } // interpolate two colors in RGBA space Color Color::InterpolateHSV(const Color& from, const Color& to, double dPercentage, bool bClockwise) { double interpolate_hue; if (bClockwise) { // positive hue double delta_hue = to.hue() - from.hue(); // MUST be positive if (delta_hue < 0.0) delta_hue += 360.0; // interpolate interpolate_hue = delta_hue*dPercentage + from.hue(); } else { // negative hue double delta_hue = to.hue() - from.hue(); // MUST be negative if (delta_hue >= 0.0) delta_hue -= 360.0; // interpolate interpolate_hue = delta_hue*dPercentage + from.hue(); } // interpolate double interpolate_sat = (to.saturation() - from.saturation())*dPercentage + from.saturation(); double interpolate_val = (to.value() - from.value()) *dPercentage + from.value(); // get RGB from HSV Color result = hsv(interpolate_hue, interpolate_sat, interpolate_val); // interpolate alpha channel return Color(result[0], result[1], result[2], from[3]*(1-dPercentage) + to[3]*dPercentage); } ostream& operator<<(ostream& ostr, const Color& mc) { ostr << mc[0] << " " << mc[1] << " " << mc[2] << " " << mc[3] << " "; return ostr; } istream& operator>>(istream& s, Color& mc) { char ch; s >> ch; if(ch =='{') { // format "{ r g b a }" s >> mc[0] >> mc[1] >> mc[2] >> mc[3] >> ch; if (ch != '}') { s.clear(ios::badbit); } } else { // format "r g b a" s.putback(ch); s >> mc[0] >> mc[1] >> mc[2] >> mc[3]; } return s; }