#pragma once #include "Utils.h" #include "Isaac.h" /// /// Palette class. /// namespace EmberNs { /// /// The palette stores a set of 256 colors which are what get accumulated to the histogram /// for each iteration. The colors come from either the main palette Xml file or directly /// from the ember parameter file. Either way, they come in as 0-255 and get normalized to 0-1. /// In the future, 2D palette support might be added in which case this class will have to be modified. /// Template argument expected to be float or double. /// template class EMBER_API Palette { public: /// /// Constructor which sets the palette index to random and allocates space to hold the color entries. /// Palette() { m_Name = "-"; m_Index = -1; m_Entries.resize(COLORMAP_LENGTH); Clear(); } /// /// Constructor that takes a name various parameters. If no color buffer is specified, a default is used. /// This is a safety fallback, and it's highly recommended to always supply a buffer of color entries. /// /// The name of the palette /// The index in the palette file /// The size of the palette which should be 256 /// A pointer to 256 color entries Palette(const string& name, int index, uint size, v4T* xmlPaletteEntries) { m_Name = name; m_Index = index; m_Entries.resize(size); if (xmlPaletteEntries) { memcpy(&m_Entries[0], xmlPaletteEntries, Size() * sizeof(m_Entries[0])); } else//They passed in null, so just fill with hard coded values so they at least have something. { //Palette 15 used in the test ember file. byte palette15[COLORMAP_LENGTH * 4] = { 0x00, 0xda, 0xde, 0xbc, 0x00, 0xee, 0xe6, 0xc5, 0x00, 0xee, 0xf2, 0xce, 0x00, 0xee, 0xf2, 0xcf, 0x00, 0xe6, 0xee, 0xe1, 0x00, 0xea, 0xee, 0xd8, 0x00, 0xf2, 0xf1, 0xeb, 0x00, 0xf2, 0xf5, 0xd8, 0x00, 0xe6, 0xf2, 0xce, 0x00, 0xde, 0xea, 0xc5, 0x00, 0xd6, 0xda, 0xc6, 0x00, 0xce, 0xd2, 0xbc, 0x00, 0xc2, 0xca, 0xa9, 0x00, 0xbe, 0xca, 0xa0, 0x00, 0xce, 0xd6, 0xaa, 0x00, 0xde, 0xe2, 0xc5, 0x00, 0xea, 0xed, 0xce, 0x00, 0xea, 0xf2, 0xc5, 0x00, 0xde, 0xe2, 0xc5, 0x00, 0xc2, 0xca, 0xaa, 0x00, 0xae, 0xbe, 0xaa, 0x00, 0xa5, 0xb2, 0x96, 0x00, 0xa2, 0xa9, 0x8d, 0x00, 0x96, 0xa2, 0x84, 0x00, 0x8d, 0x8d, 0x7a, 0x00, 0x85, 0x89, 0x71, 0x00, 0x85, 0x8d, 0x71, 0x00, 0x85, 0x85, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x79, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, 0x00, 0x65, 0x6d, 0x55, 0x00, 0x4d, 0x5d, 0x42, 0x00, 0x34, 0x40, 0x25, 0x00, 0x30, 0x40, 0x25, 0x00, 0x30, 0x38, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x2c, 0x34, 0x1c, 0x00, 0x24, 0x2c, 0x12, 0x00, 0x24, 0x24, 0x00, 0x00, 0x24, 0x2c, 0x09, 0x00, 0x28, 0x34, 0x09, 0x00, 0x38, 0x40, 0x12, 0x00, 0x30, 0x40, 0x1c, 0x00, 0x40, 0x50, 0x2f, 0x00, 0x55, 0x69, 0x42, 0x00, 0x65, 0x75, 0x55, 0x00, 0x6c, 0x7d, 0x5e, 0x00, 0x74, 0x8d, 0x71, 0x00, 0x74, 0x89, 0x84, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x78, 0x8d, 0x84, 0x00, 0x79, 0x89, 0x7a, 0x00, 0x79, 0x85, 0x71, 0x00, 0x75, 0x7d, 0x67, 0x00, 0x71, 0x79, 0x5e, 0x00, 0x6c, 0x71, 0x5e, 0x00, 0x6d, 0x70, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x69, 0x71, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x71, 0x55, 0x00, 0x65, 0x71, 0x55, 0x00, 0x69, 0x6d, 0x55, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x70, 0x67, 0x00, 0x68, 0x6c, 0x67, 0x00, 0x6c, 0x6c, 0x5e, 0x00, 0x71, 0x71, 0x5e, 0x00, 0x79, 0x79, 0x67, 0x00, 0x81, 0x85, 0x71, 0x00, 0x7d, 0x91, 0x71, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x85, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x79, 0x92, 0x84, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x78, 0x8d, 0x8d, 0x00, 0x74, 0x8d, 0x84, 0x00, 0x74, 0x92, 0x84, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x6c, 0x85, 0x67, 0x00, 0x64, 0x79, 0x5e, 0x00, 0x59, 0x69, 0x4b, 0x00, 0xaa, 0x57, 0x00, 0x00, 0x38, 0x44, 0x1c, 0x00, 0x30, 0x3c, 0x1c, 0x00, 0x2c, 0x3c, 0x1c, 0x00, 0x34, 0x40, 0x25, 0x00, 0x50, 0x61, 0x4b, 0x00, 0x5d, 0x6d, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x60, 0x71, 0x5e, 0x00, 0x60, 0x75, 0x5e, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x71, 0x79, 0x67, 0x00, 0x70, 0x79, 0x67, 0x00, 0x6c, 0x7d, 0x67, 0x00, 0x68, 0x79, 0x67, 0x00, 0x6c, 0x79, 0x67, 0x00, 0x6c, 0x75, 0x67, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x71, 0x75, 0x5e, 0x00, 0x75, 0x79, 0x5e, 0x00, 0x75, 0x7d, 0x5e, 0x00, 0x81, 0x8d, 0x5e, 0x00, 0x8d, 0x92, 0x5e, 0x00, 0x8d, 0x92, 0x67, 0x00, 0x9a, 0x9a, 0x71, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9a, 0xa1, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x92, 0x67, 0x00, 0x81, 0x85, 0x5e, 0x00, 0x7d, 0x7d, 0x55, 0x00, 0x69, 0x79, 0x4b, 0x00, 0x61, 0x6d, 0x42, 0x00, 0x44, 0x4c, 0x25, 0x00, 0x38, 0x44, 0x1c, 0x00, 0x40, 0x51, 0x25, 0x00, 0x45, 0x4d, 0x25, 0x00, 0x71, 0x6d, 0x42, 0x00, 0x79, 0x7d, 0x4b, 0x00, 0x81, 0x7d, 0x55, 0x00, 0x79, 0x79, 0x55, 0x00, 0x6d, 0x75, 0x55, 0x00, 0x69, 0x7d, 0x55, 0x00, 0x6c, 0x79, 0x5e, 0x00, 0x65, 0x79, 0x54, 0x00, 0x68, 0x79, 0x5e, 0x00, 0x64, 0x79, 0x67, 0x00, 0x64, 0x79, 0x67, 0x00, 0x68, 0x75, 0x5e, 0x00, 0x64, 0x71, 0x5e, 0x00, 0x64, 0x6c, 0x5e, 0x00, 0x65, 0x6d, 0x55, 0x00, 0x4d, 0x58, 0x42, 0x00, 0x34, 0x40, 0x25, 0x00, 0x2c, 0x38, 0x1c, 0x00, 0x20, 0x28, 0x1c, 0x00, 0x1c, 0x14, 0x09, 0x00, 0x18, 0x18, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x0c, 0x18, 0x00, 0x00, 0x1c, 0x28, 0x09, 0x00, 0x24, 0x30, 0x12, 0x00, 0x3c, 0x44, 0x25, 0x00, 0x5d, 0x65, 0x55, 0x00, 0x75, 0x79, 0x55, 0x00, 0x85, 0x89, 0x5e, 0x00, 0x89, 0x91, 0x71, 0x00, 0x96, 0xa2, 0x71, 0x00, 0x9a, 0xa2, 0x7a, 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xae, 0x71, 0x00, 0xa6, 0xaa, 0x7a, 0x00, 0xa2, 0xaa, 0x7a, 0x00, 0xa1, 0xa5, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x85, 0x96, 0x7a, 0x00, 0x81, 0x92, 0x7a, 0x00, 0x78, 0x92, 0x7a, 0x00, 0x75, 0x92, 0x7a, 0x00, 0x75, 0x8d, 0x7a, 0x00, 0x70, 0x81, 0x67, 0x00, 0x7d, 0x7d, 0x67, 0x00, 0x89, 0x89, 0x67, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x9e, 0xaa, 0x7a, 0x00, 0xaa, 0xb6, 0x84, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xb6, 0xba, 0x97, 0x00, 0xc2, 0xca, 0x97, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb2, 0xb6, 0x8d, 0x00, 0xaa, 0xb2, 0x8d, 0x00, 0xa2, 0xae, 0x84, 0x00, 0x9a, 0xa6, 0x7a, 0x00, 0x92, 0x9e, 0x7a, 0x00, 0x85, 0x9a, 0x7a, 0x00, 0x7d, 0x96, 0x7a, 0x00, 0x7d, 0x92, 0x7a, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x84, 0x00, 0x81, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x85, 0x96, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x85, 0x9a, 0x84, 0x00, 0x8d, 0x9a, 0x84, 0x00, 0x92, 0x96, 0x84, 0x00, 0x9e, 0xa9, 0x84, 0x00, 0xae, 0xb2, 0x84, 0x00, 0xaa, 0xba, 0x84, 0x00, 0xb2, 0xbe, 0x8d, 0x00, 0xb6, 0xc2, 0xa0, 0x00, 0xc6, 0xca, 0xa0, 0x00, 0xc6, 0xce, 0xaa, 0x00, 0xd6, 0xda, 0xb3, 0x00, 0xda, 0xe2, 0xc5, 0x00, 0xd2, 0xd6, 0xbc, 0x00, 0xbe, 0xc2, 0xa0, 0x00, 0xaa, 0xb6, 0x8d, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0x92, 0x9a, 0x71, 0x00, 0x89, 0x89, 0x71, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x7d, 0x7d, 0x67, 0x00, 0x81, 0x78, 0x67, 0x00, 0x7d, 0x7d, 0x5e, 0x00, 0x79, 0x79, 0x5e, 0x00, 0x79, 0x81, 0x5e, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x7d, 0x67, 0x00, 0x81, 0x81, 0x67, 0x00, 0x81, 0x89, 0x71, 0x00, 0x85, 0x91, 0x7a, 0x00, 0x89, 0x92, 0x7a, 0x00, 0x96, 0x9d, 0x7a, 0x00, 0x96, 0x9e, 0x7a, 0x00, 0x92, 0x96, 0x84, 0x00, 0x96, 0x9a, 0x8d, 0x00, 0x92, 0x92, 0x84, 0x00, 0x89, 0x91, 0x84, 0x00, 0x81, 0x92, 0x84, 0x00, 0x7d, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x74, 0x92, 0x8d, 0x00, 0x78, 0x92, 0x8d, 0x00, 0x78, 0x96, 0x97, 0x00, 0x81, 0x96, 0x8d, 0x00, 0x81, 0x96, 0x8d, 0x00, 0x81, 0x9a, 0x8d, 0x00, 0x85, 0x9a, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x89, 0x9e, 0x8d, 0x00, 0x8d, 0xa2, 0x97, 0x00, 0x95, 0xa2, 0x97, 0x00, 0x8d, 0xa2, 0x97, 0x00, 0x96, 0xa6, 0x8d, 0x00, 0x9a, 0xa1, 0x8d, 0x00, 0x9e, 0xa9, 0x84, 0x00, 0x9e, 0xa6, 0x7a, 0x00, 0xa2, 0xa5, 0x71, 0x00, 0x9e, 0xa6, 0x71, 0x00, 0x9a, 0xa6, 0x71, 0x00, 0x95, 0x9d, 0x71 }; for (uint i = 0; i < size; i++) { m_Entries[i].a = T(palette15[i * 4 + 0]); m_Entries[i].r = T(palette15[i * 4 + 1]); m_Entries[i].g = T(palette15[i * 4 + 2]); m_Entries[i].b = T(palette15[i * 4 + 3]); } } } /// /// Default copy constructor. /// /// The Palette object to copy Palette(const Palette& palette) { Palette::operator=(palette); } /// /// Copy constructor to copy a Palette object of type U. /// /// The Palette object to copy template Palette(const Palette& palette) { Palette::operator=(palette); } /// /// Empty destructor. /// Needed to eliminate warnings about inlining. /// ~Palette() { } /// /// Default assignment operator. /// /// The Palette object to copy Palette& operator = (const Palette& palette) { if (this != &palette) Palette::operator=(palette); return *this; } /// /// Assignment operator to assign a Palette object of type U. /// /// The Palette object to copy /// Reference to updated self template Palette& operator = (const Palette& palette) { m_Index = palette.m_Index; m_Name = palette.m_Name; m_Filename = palette.m_Filename; CopyVec(m_Entries, palette.m_Entries); return *this; } /// /// Convenience [] operator to index into the color entries vector. /// /// The index to get /// The color value at the specified index v4T& operator[] (size_t i) { return m_Entries[i]; } /// /// Convenience * operator to get a pointer to the beginning of the color entries vector. /// /// The address of the first element in the color entries vector inline v4T* operator() (void) { return &m_Entries[0]; } /// /// The size of the color entries vector. /// /// The size of the color entries vector size_t Size() { return m_Entries.size(); } /// /// Set all colors to either black or white, including the alpha channel. /// /// Set all colors to black if true, else white void Clear(bool black = true) { for (glm::length_t i = 0; i < Size(); i++) { for (glm::length_t j = 0; j < 4; j++) { if (black) m_Entries[i][j] = 0; else m_Entries[i][j] = 1; } } } /// /// Make a copy of this palette, adjust for hue and store in the passed in palette. /// This is used because one way an ember Xml can specify color is with an index in the /// palette Xml file and a hue rotation value. /// /// The palette to store the results in /// The hue rotation to apply void MakeHueAdjustedPalette(Palette& palette, T hue) { palette.m_Index = m_Index; palette.m_Name = m_Name; palette.m_Filename = m_Filename; palette.m_Entries.resize(Size()); for (uint i = 0; i < Size(); i++) { size_t ii = (i * 256) / COLORMAP_LENGTH; T rgb[3], hsv[3]; rgb[0] = m_Entries[ii].r; rgb[1] = m_Entries[ii].g; rgb[2] = m_Entries[ii].b; RgbToHsv(rgb, hsv); hsv[0] += hue * T(6.0); HsvToRgb(hsv, rgb); //Alpha serves as merely a hit counter that gets incremented by 1 each time, see Renderer::Accumulate() for its usage. //Removing it saves no memory since it's 16 byte aligned. This also means alpha is not used. palette[i].r = rgb[0]; palette[i].g = rgb[1]; palette[i].b = rgb[2]; palette[i].a = 1; } } /// /// More advanced adjustment than MakeHueAdjustedPalette() provides. /// Adjustments are applied in the order: /// Frequency, index rotation, hue rotation, saturation, brightness, contrast, blur. /// /// The palette to store the result in /// Index rotation. /// Hue rotation -5 - 5 /// Saturation 0 - 1 /// Brightness 0 - 1 /// Contrast -1 - 2 /// Blur 0 - 127 /// Frequency 1 - 10 void MakeAdjustedPalette(Palette& palette, int rot, T hue, T sat, T bright, T cont, uint blur, uint freq) { T rgb[3], hsv[3]; if (freq > 1) { size_t n = Size() / freq; for (size_t j = 0; j <= freq; j++) { for (size_t i = 0; i <= n; i++) { if ((i + j * n) < Size()) { palette[i + j * n].r = m_Entries[i * freq].r; palette[i + j * n].g = m_Entries[i * freq].g; palette[i + j * n].b = m_Entries[i * freq].b; } } } palette.m_Name = m_Name; palette.m_Filename = m_Filename; } else { palette = *this; } for (size_t i = 0; i < Size(); i++) { size_t ii = (i * 256) / COLORMAP_LENGTH; rgb[0] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].r;//Rotation. rgb[1] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].g; rgb[2] = palette[(COLORMAP_LENGTH + ii - rot) % COLORMAP_LENGTH].b; RgbToHsv(rgb, hsv); hsv[0] += hue * T(6.0);//Hue. hsv[1] = Clamp(hsv[1] + sat, 0, 1);//Saturation. HsvToRgb(hsv, rgb); rgb[0] = Clamp(rgb[0] + bright, 0, 1);//Brightness. rgb[1] = Clamp(rgb[1] + bright, 0, 1); rgb[2] = Clamp(rgb[2] + bright, 0, 1); rgb[0] = Clamp(((rgb[0] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1);//Contrast. rgb[1] = Clamp(((rgb[1] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1); rgb[2] = Clamp(((rgb[2] - T(0.5)) * (cont + T(1.0))) + T(0.5), 0, 1); //Alpha serves as merely a hit counter that gets incremented by 1 each time, see Renderer::Accumulate() for its usage. //Removing it saves no memory since it's 16 byte aligned. palette[i].r = rgb[0]; palette[i].g = rgb[1]; palette[i].b = rgb[2]; palette[i].a = 1; } if (blur > 0) { Palette blurPal = palette; for (int i = 0; i < 256; i++) { int n = -1; rgb[0] = 0; rgb[1] = 0; rgb[2] = 0; for (int j = i - int(blur); j <= i + int(blur); j++) { n++; int k = (256 + j) % 256; if (k != i) { rgb[0] = rgb[0] + blurPal[k].r; rgb[1] = rgb[1] + blurPal[k].g; rgb[2] = rgb[2] + blurPal[k].b; } } if (n != 0) { palette[i].r = rgb[0] / n; palette[i].g = rgb[1] / n; palette[i].b = rgb[2] / n; } } } } /// /// Make a copy of this palette and multiply all RGB values by a scalar. /// /// The palette to store the result in /// The color scalar to multiply each RGB value by template void MakeDmap(Palette& palette, T colorScalar = 1) { palette.m_Index = m_Index; palette.m_Name = m_Name; palette.m_Filename = m_Filename; if (palette.Size() != Size()) palette.m_Entries.resize(Size()); for (uint j = 0; j < palette.Size(); j++) { palette.m_Entries[j] = m_Entries[j] * colorScalar; palette.m_Entries[j].a = 1; } } /// /// Make a buffer with the color values of this palette scaled to 255 /// and repeated for a number of rows. /// Convenience function for displaying this palette on a GUI. /// /// The height of the output block /// A vector holding the color values vector MakeRgbPaletteBlock(uint height) { size_t width = Size(); vector v(height * width * 3); if (v.size() == (height * Size() * 3)) { for (uint i = 0; i < height; i++) { for (uint j = 0; j < width; j++) { v[(width * 3 * i) + (j * 3)] = byte(m_Entries[j][0] * T(255));//Palettes are as [0..1], so convert to [0..255] here since it's for GUI display. v[(width * 3 * i) + (j * 3) + 1] = byte(m_Entries[j][1] * T(255)); v[(width * 3 * i) + (j * 3) + 2] = byte(m_Entries[j][2] * T(255)); } } } return v; } /// /// Convert RGB to HSV. /// /// Red 0 - 1 /// Green 0 - 1 /// Blue 0 - 1 /// Hue 0 - 6 /// Saturation 0 - 1 /// Value 0 - 1 static void RgbToHsv(T r, T g, T b, T& h, T& s, T& v) { T max, min, del, rc, gc, bc; max = std::max(std::max(r, g), b);//Compute maximum of r, g, b. min = std::min(std::min(r, g), b);//Compute minimum of r, g, b. del = max - min; v = max; s = (max != 0) ? (del / max) : 0; h = 0; if (s != 0) { rc = (max - r) / del; gc = (max - g) / del; bc = (max - b) / del; if (r == max) h = bc - gc; else if (g == max) h = 2 + rc - bc; else if (b == max) h = 4 + gc - rc; if (h < 0) h += 6; } } /// /// Wrapper around RgbToHsv() which takes buffers as parameters instead of individual components. /// /// The RGB buffer /// The HSV buffer static void RgbToHsv(T* rgb, T* hsv) { RgbToHsv(rgb[0], rgb[1], rgb[2], hsv[0], hsv[1], hsv[2]); } /// /// Convert HSV to RGB. /// /// Hue 0 - 6 /// Saturation 0 - 1 /// Value 0 - 1 /// Red 0 - 1 /// Green 0 - 1 /// Blue 0 - 1 static void HsvToRgb(T h, T s, T v, T& r, T& g, T& b) { int j; T f, p, q, t; while (h >= 6) h -= 6; while (h < 0) h += 6; j = Floor(h); f = h - j; p = v * (1 - s); q = v * (1 - (s * f)); t = v * (1 - (s * (1 - f))); switch (j) { 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: r = v; g = t; b = p; break; } } /// /// Wrapper around HsvToRgb() which takes buffers as parameters instead of individual components. /// /// The HSV buffer /// The RGB buffer static void HsvToRgb(T* hsv, T* rgb) { HsvToRgb(hsv[0], hsv[1], hsv[2], rgb[0], rgb[1], rgb[2]); } /// /// Calculates the alpha. /// Used for gamma correction in final accumulation. /// Not the slightest clue what this is doing. /// /// Density /// Gamma /// Linear range /// Alpha static T CalcAlpha(T density, T gamma, T linrange) { T frac, alpha; T funcval = pow(linrange, gamma); if (density > 0) { if (density < linrange) { frac = density / linrange; alpha = (T(1.0) - frac) * density * (funcval / linrange) + frac * pow(density, gamma); } else alpha = pow(density, gamma); } else alpha = 0; return alpha; } /// /// Calculates the new RGB and stores in the supplied buffer. /// Used for gamma correction in final accumulation. /// Not the slightest clue what this is doing. /// /// The input RGB color buffer 0 - 1 /// Log scaling /// Highlight power, -1 - 1 /// Newly computed RGB value template static void CalcNewRgb(bucketT* cBuf, T ls, T highPow, bucketT* newRgb) { int rgbi; T newls, lsratio; bucketT newhsv[3]; T maxa, maxc; T adjustedHighlight; if (ls == 0 || (cBuf[0] == 0 && cBuf[1] == 0 && cBuf[2] == 0)) { newRgb[0] = 0; newRgb[1] = 0; newRgb[2] = 0; return; } //Identify the most saturated channel. maxc = std::max(std::max(cBuf[0], cBuf[1]), cBuf[2]); maxa = ls * maxc; //If a channel is saturated and highlight power is non-negative //modify the color to prevent hue shift. if (maxa > 255 && highPow >= 0) { newls = T(255.0) / maxc; lsratio = pow(newls / ls, highPow); //Calculate the max-value color (ranged 0 - 1). for (rgbi = 0; rgbi < 3; rgbi++) newRgb[rgbi] = bucketT(newls) * cBuf[rgbi] / bucketT(255.0); //Reduce saturation by the lsratio. Palette::RgbToHsv(newRgb, newhsv); newhsv[1] *= bucketT(lsratio); Palette::HsvToRgb(newhsv, newRgb); for (rgbi = 0; rgbi < 3; rgbi++) newRgb[rgbi] *= T(255.0); } else { newls = T(255.0) / maxc; adjustedHighlight = -highPow; if (adjustedHighlight > 1) adjustedHighlight = 1; if (maxa <= 255) adjustedHighlight = 1; //Calculate the max-value color (ranged 0 - 1) interpolated with the old behavior. for (rgbi = 0; rgbi < 3; rgbi++) newRgb[rgbi] = bucketT((T(1.0) - adjustedHighlight) * newls + adjustedHighlight * ls) * cBuf[rgbi]; } } int m_Index;//Index in the xml palette file of this palette, use -1 for random. string m_Name;//Name of this palette. shared_ptr m_Filename;//Name of the parent file this palette came from, can be empty. vector m_Entries;//Storage for the color values. }; }