1/* 2 * Copyright 2001-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 */ 8 9 10#include "RGBColor.h" 11#include "SystemPalette.h" 12 13#include <stdio.h> 14#include <stdlib.h> 15 16 17/*! 18 \brief An approximation of 31/255, which is needed for converting from 32-bit 19 colors to 16-bit and 15-bit. 20*/ 21#define RATIO_8_TO_5_BIT .121568627451 22 23/*! 24 \brief An approximation of 63/255, which is needed for converting from 32-bit 25 colors to 16-bit. 26*/ 27#define RATIO_8_TO_6_BIT .247058823529 28 29/*! 30 \brief An approximation of 255/31, which is needed for converting from 16-bit 31 and 15-bit colors to 32-bit. 32*/ 33#define RATIO_5_TO_8_BIT 8.22580645161 34 35/*! 36 \brief An approximation of 255/63, which is needed for converting from 16-bit 37 colors to 32-bit. 38*/ 39#define RATIO_6_TO_8_BIT 4.04761904762 40 41#if 0 42/*! 43 \brief Function for easy conversion of 16-bit colors to 32-bit 44 \param col Pointer to an rgb_color. 45 \param color RGB16 color 46 47 This function will do nothing if passed a NULL 32-bit color. 48*/ 49void 50SetRGBColor16(rgb_color *col,uint16 color) 51{ 52 if(!col) 53 return; 54 55 uint16 r16,g16,b16; 56 57 // alpha's the easy part 58 col->alpha=0; 59 60 r16= (color >> 11) & 31; 61 g16= (color >> 5) & 63; 62 b16= color & 31; 63 64 col->red=uint8(r16 * RATIO_5_TO_8_BIT); 65 col->green=uint8(g16 * RATIO_6_TO_8_BIT); 66 col->blue=uint8(b16 * RATIO_5_TO_8_BIT); 67} 68#endif 69 70/*! 71 \brief Finds the index of the closest matching color in a rgb_color palette array 72 \param palette Array of 256 rgb_color objects 73 \param color Color to match 74 \return Index of the closest matching color 75 76 Note that passing a NULL palette will always return 0 and passing an array of less 77 than 256 rgb_colors will cause a crash. 78*/ 79static uint8 80FindClosestColor(const rgb_color *palette, rgb_color color) 81{ 82 if (!palette) 83 return 0; 84 85 uint16 cindex = 0, cdelta = 765, delta = 765; 86 87 for (uint16 i = 0; i < 256; i++) { 88 const rgb_color *c = &(palette[i]); 89 delta = abs(c->red-color.red) + abs(c->green-color.green) 90 + abs(c->blue-color.blue); 91 92 if (delta == 0) { 93 cindex = i; 94 break; 95 } 96 97 if (delta < cdelta) { 98 cindex = i; 99 cdelta = delta; 100 } 101 } 102 103 return (uint8)cindex; 104} 105 106 107/*! 108 \brief Constructs a RGBA15 color which best matches a given 32-bit color 109 \param color Color to match 110 \return The closest matching color's value 111 112 Format is ARGB, 1:5:5:5 113*/ 114static uint16 115FindClosestColor15(rgb_color color) 116{ 117 uint16 r16 = uint16(color.red * RATIO_8_TO_5_BIT); 118 uint16 g16 = uint16(color.green * RATIO_8_TO_5_BIT); 119 uint16 b16 = uint16(color.blue * RATIO_8_TO_5_BIT); 120 121 // start with alpha value 122 uint16 color16 = color.alpha > 127 ? 0x8000 : 0; 123 124 color16 |= r16 << 10; 125 color16 |= g16 << 5; 126 color16 |= b16; 127 128 return color16; 129} 130 131 132/*! 133 \brief Constructs a RGB16 color which best matches a given 32-bit color 134 \param color Color to match 135 \return The closest matching color's value 136 137 Format is RGB, 5:6:5 138*/ 139static uint16 140FindClosestColor16(rgb_color color) 141{ 142 uint16 r16 = uint16(color.red * RATIO_8_TO_5_BIT); 143 uint16 g16 = uint16(color.green * RATIO_8_TO_6_BIT); 144 uint16 b16 = uint16(color.blue * RATIO_8_TO_5_BIT); 145 146 uint16 color16 = r16 << 11; 147 color16 |= g16 << 5; 148 color16 |= b16; 149 150 return color16; 151} 152 153 154// #pragma mark - 155 156 157/*! 158 \brief Create an RGBColor from specified values 159 \param red red 160 \param green green 161 \param blue blue 162 \param alpha alpha, defaults to 255 163*/ 164RGBColor::RGBColor(uint8 r, uint8 g, uint8 b, uint8 a) 165{ 166 SetColor(r,g,b,a); 167} 168 169 170/*! 171 \brief Create an RGBColor from specified values 172 \param red red 173 \param green green 174 \param blue blue 175 \param alpha alpha, defaults to 255 176*/ 177RGBColor::RGBColor(int r, int g, int b, int a) 178{ 179 SetColor(r, g, b, a); 180} 181 182 183/*! 184 \brief Create an RGBColor from an rgb_color 185 \param color color to initialize from 186*/ 187RGBColor::RGBColor(const rgb_color &color) 188{ 189 SetColor(color); 190} 191 192#if 0 193/*! 194 \brief Create an RGBColor from a 16-bit RGBA color 195 \param color color to initialize from 196*/ 197RGBColor::RGBColor(uint16 color) 198{ 199 SetColor(color); 200} 201#endif 202 203/*! 204 \brief Create an RGBColor from an index color 205 \param color color to initialize from 206*/ 207RGBColor::RGBColor(uint8 color) 208{ 209 SetColor(color); 210} 211 212 213/*! 214 \brief Copy Contructor 215 \param color color to initialize from 216*/ 217RGBColor::RGBColor(const RGBColor &color) 218{ 219 fColor32 = color.fColor32; 220 fColor16 = color.fColor16; 221 fColor15 = color.fColor15; 222 fColor8 = color.fColor8; 223 fUpdate8 = color.fUpdate8; 224 fUpdate15 = color.fUpdate15; 225 fUpdate16 = color.fUpdate16; 226} 227 228 229/*! 230 \brief Create an RGBColor with the values(0,0,0,0) 231*/ 232RGBColor::RGBColor() 233{ 234 SetColor(0, 0, 0, 0); 235} 236 237 238/*! 239 \brief Returns the color as the closest 8-bit color in the palette 240 \return The palette index for the current color 241*/ 242uint8 243RGBColor::GetColor8() const 244{ 245 if (fUpdate8) { 246 fColor8 = FindClosestColor(SystemPalette(), fColor32); 247 fUpdate8 = false; 248 } 249 250 return fColor8; 251} 252 253 254/*! 255 \brief Returns the color as the closest 15-bit color 256 \return 15-bit value of the current color plus 1-bit alpha 257*/ 258uint16 259RGBColor::GetColor15() const 260{ 261 if (fUpdate15) { 262 fColor15 = FindClosestColor15(fColor32); 263 fUpdate15 = false; 264 } 265 266 return fColor15; 267} 268 269 270/*! 271 \brief Returns the color as the closest 16-bit color 272 \return 16-bit value of the current color 273*/ 274uint16 275RGBColor::GetColor16() const 276{ 277 if (fUpdate16) { 278 fColor16 = FindClosestColor16(fColor32); 279 fUpdate16 = false; 280 } 281 282 return fColor16; 283} 284 285 286/*! 287 \brief Returns the color as a 32-bit color 288 \return current color, including alpha 289*/ 290rgb_color 291RGBColor::GetColor32() const 292{ 293 return fColor32; 294} 295 296 297/*! 298 \brief Set the object to specified values 299 \param red red 300 \param green green 301 \param blue blue 302 \param alpha alpha, defaults to 255 303*/ 304void 305RGBColor::SetColor(uint8 r, uint8 g, uint8 b, uint8 a) 306{ 307 fColor32.red = r; 308 fColor32.green = g; 309 fColor32.blue = b; 310 fColor32.alpha = a; 311 312 fUpdate8 = fUpdate15 = fUpdate16 = true; 313} 314 315 316/*! 317 \brief Set the object to specified values 318 \param red red 319 \param green green 320 \param blue blue 321 \param alpha alpha, defaults to 255 322*/ 323void 324RGBColor::SetColor(int r, int g, int b, int a) 325{ 326 fColor32.red = (uint8)r; 327 fColor32.green = (uint8)g; 328 fColor32.blue = (uint8)b; 329 fColor32.alpha = (uint8)a; 330 331 fUpdate8 = fUpdate15 = fUpdate16 = true; 332} 333 334#if 0 335/*! 336 \brief Set the object to specified value 337 \param col16 color to copy 338*/ 339void 340RGBColor::SetColor(uint16 col16) 341{ 342 fColor16 = col16; 343 SetRGBColor(&fColor32, col16); 344 345 fUpdate8 = true; 346 fUpdate15 = true; 347 fUpdate16 = false; 348} 349#endif 350 351 352/*! 353 \brief Set the object to specified index in the palette 354 \param col8 color to copy 355*/ 356void 357RGBColor::SetColor(uint8 col8) 358{ 359 fColor8 = col8; 360 fColor32 = SystemPalette()[col8]; 361 362 fUpdate8 = false; 363 fUpdate15 = true; 364 fUpdate16 = true; 365} 366 367 368/*! 369 \brief Set the object to specified color 370 \param color color to copy 371*/ 372void 373RGBColor::SetColor(const rgb_color &color) 374{ 375 fColor32 = color; 376 fUpdate8 = fUpdate15 = fUpdate16 = true; 377} 378 379 380/*! 381 \brief Set the object to specified color 382 \param color color to copy 383*/ 384void 385RGBColor::SetColor(const RGBColor &color) 386{ 387 fColor32 = color.fColor32; 388 fColor16 = color.fColor16; 389 fColor15 = color.fColor15; 390 fColor8 = color.fColor8; 391 fUpdate8 = color.fUpdate8; 392 fUpdate15 = color.fUpdate15; 393 fUpdate16 = color.fUpdate16; 394} 395 396 397/*! 398 \brief Set the object to specified color 399 \param color color to copy 400*/ 401const RGBColor& 402RGBColor::operator=(const RGBColor &color) 403{ 404 fColor32 = color.fColor32; 405 fColor16 = color.fColor16; 406 fColor15 = color.fColor15; 407 fColor8 = color.fColor8; 408 fUpdate8 = color.fUpdate8; 409 fUpdate15 = color.fUpdate15; 410 fUpdate16 = color.fUpdate16; 411 412 return *this; 413} 414 415 416/*! 417 \brief Set the object to specified color 418 \param color color to copy 419*/ 420const RGBColor& 421RGBColor::operator=(const rgb_color &color) 422{ 423 fColor32 = color; 424 fUpdate8 = fUpdate15 = fUpdate16 = true; 425 426 return *this; 427} 428 429 430/*! 431 \brief Prints the 32-bit values of the color to standard out 432*/ 433void 434RGBColor::PrintToStream(void) const 435{ 436 printf("RGBColor(%u,%u,%u,%u)\n", 437 fColor32.red, fColor32.green, fColor32.blue, fColor32.alpha); 438} 439 440 441/*! 442 \brief Overloaded comaparison 443 \return true if all color elements are exactly equal 444*/ 445bool 446RGBColor::operator==(const rgb_color &color) const 447{ 448 return fColor32.red == color.red 449 && fColor32.green == color.green 450 && fColor32.blue == color.blue 451 && fColor32.alpha == color.alpha; 452} 453 454 455/*! 456 \brief Overloaded comaparison 457 \return true if all color elements are exactly equal 458*/ 459bool 460RGBColor::operator==(const RGBColor &color) const 461{ 462 return fColor32.red == color.fColor32.red 463 && fColor32.green == color.fColor32.green 464 && fColor32.blue == color.fColor32.blue 465 && fColor32.alpha == color.fColor32.alpha; 466} 467 468 469bool 470RGBColor::operator!=(const rgb_color &color) const 471{ 472 return fColor32.red != color.red 473 || fColor32.green != color.green 474 || fColor32.blue != color.blue 475 || fColor32.alpha != color.alpha; 476} 477 478 479bool 480RGBColor::operator!=(const RGBColor &color) const 481{ 482 return fColor32.red != color.fColor32.red 483 || fColor32.green != color.fColor32.green 484 || fColor32.blue != color.fColor32.blue 485 || fColor32.alpha != color.fColor32.alpha; 486} 487 488 489bool 490RGBColor::IsTransparentMagic() const 491{ 492 // TODO: validate this for B_CMAP8 for example 493 return *this == B_TRANSPARENT_COLOR; 494} 495