2023-04-25 19:59:54 -04:00
# pragma once
# include "Utils.h"
# include "Isaac.h"
/// <summary>
/// Palette class.
/// </summary>
namespace EmberNs
{
/// <summary>
/// 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.
/// The palette may have also come from a palette editor where the user specifies key colors, then
/// those are interpolated to make a smooth palette. In that case, the m_SourceColors map will
/// be populated.
/// 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.
/// </summary>
template < typename T >
class EMBER_API Palette
{
public :
/// <summary>
/// Constructor which sets the palette index to random and allocates space to hold the color entries.
/// </summary>
Palette ( )
{
m_Entries . resize ( COLORMAP_LENGTH ) ;
Clear ( ) ;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="name">The name of the palette</param>
/// <param name="index">The index in the palette file</param>
/// <param name="size">The size of the palette which should be 256</param>
/// <param name="xmlPaletteEntries">A pointer to 256 color entries</param>
Palette ( const string & name , int index , size_t size , v4T * xmlPaletteEntries )
{
m_Name = name ;
m_Index = index ;
m_Entries . resize ( size ) ;
if ( xmlPaletteEntries )
{
memcpy ( m_Entries . data ( ) , xmlPaletteEntries , SizeOf ( m_Entries ) ) ;
//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.
unsigned char 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 ( size_t i = 0 ; i < size ; i + + )
{
m_Entries [ i ] . a = T ( palette15 [ i * 4 + 0 ] ) ;
m_Entries [ i ] . r = T ( palette15 [ i * 4 + 1 ] ) / T ( 255 ) ;
m_Entries [ i ] . g = T ( palette15 [ i * 4 + 2 ] ) / T ( 255 ) ;
m_Entries [ i ] . b = T ( palette15 [ i * 4 + 3 ] ) / T ( 255 ) ;
}
}
}
/// <summary>
/// Constructor which takes the vector of colors as well as the source colors which were
/// used to create it in a palette editor. The burden is on the user to not let the two get out of sync.
/// </summary>
/// <param name="name">The name of the palette</param>
/// <param name="entries">A vector of color entries</param>
/// <param name="sourceColors">A map of colors which was used to create entries in a palette editor</param>
Palette ( const string & name , vector < v4T > & entries , map < T , v4T > & sourceColors )
{
m_Name = name ;
m_Entries = entries ;
m_SourceColors = sourceColors ;
}
/// <summary>
/// Default copy constructor.
/// </summary>
/// <param name="palette">The Palette object to copy</param>
Palette ( const Palette < T > & palette )
{
Palette < T > : : operator = < T > ( palette ) ;
}
/// <summary>
/// Copy constructor to copy a Palette object of type U.
/// </summary>
/// <param name="palette">The Palette object to copy</param>
template < typename U >
Palette ( const Palette < U > & palette )
{
Palette < T > : : operator = < U > ( palette ) ;
}
/// <summary>
/// Needed to eliminate warnings about inlining.
/// </summary>
~ Palette ( ) = default ;
/// <summary>
/// Default assignment operator.
/// </summary>
/// <param name="palette">The Palette object to copy</param>
Palette < T > & operator = ( const Palette < T > & palette )
{
if ( this ! = & palette )
Palette < T > : : operator = < T > ( palette ) ;
return * this ;
}
/// <summary>
/// Assignment operator to assign a Palette object of type U.
/// </summary>
/// <param name="palette">The Palette object to copy</param>
/// <returns>Reference to updated self</returns>
template < typename U >
Palette < T > & operator = ( const Palette < U > & palette )
{
m_Index = palette . m_Index ;
m_Name = palette . m_Name ;
m_Filename = palette . m_Filename ;
CopyCont ( m_Entries , palette . m_Entries ) ;
m_SourceColors . clear ( ) ;
for ( auto & kv : palette . m_SourceColors )
m_SourceColors [ T ( kv . first ) ] = v4T ( kv . second ) ;
return * this ;
}
/// <summary>
/// Convenience [] operator to index into the color entries vector.
/// </summary>
/// <param name="i">The index to get</param>
/// <returns>The color value at the specified index</returns>
v4T & operator [ ] ( size_t i )
{
return m_Entries [ i ] ;
}
/// <summary>
/// Convenience [] operator to index into the color entries vector in a const context.
/// </summary>
/// <param name="i">The index to get</param>
/// <returns>The color value at the specified index</returns>
const v4T & operator [ ] ( size_t i ) const
{
return m_Entries [ i ] ;
}
/// <summary>
/// Convenience * operator to get a pointer to the beginning of the color entries vector.
/// </summary>
/// <returns>The address of the first element in the color entries vector</returns>
inline v4T * operator ( ) ( void )
{
return m_Entries . data ( ) ;
}
/// <summary>
/// The size of the color entries vector.
/// </summary>
/// <returns>The size of the color entries vector</returns>
size_t Size ( ) { return m_Entries . size ( ) ; }
/// <summary>
/// The size of the source color entries vector which was used to create the palette.
/// Note this will only be non-zero if this palette was created in the palette editor.
/// </summary>
/// <returns>The size of the source colors map</returns>
size_t SourceColorSize ( ) { return m_SourceColors . size ( ) ; }
/// <summary>
/// Set all colors to either black or white, including the alpha channel.
/// </summary>
/// <param name="black">Set all colors to black if true, else white</param>
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 ;
}
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="palette">The palette to store the results in</param>
/// <param name="hue">The hue rotation to apply</param>
void MakeHueAdjustedPalette ( Palette < T > & palette , T hue )
{
palette . m_Index = m_Index ;
palette . m_Name = m_Name ;
palette . m_Filename = m_Filename ;
palette . m_Entries . resize ( Size ( ) ) ;
for ( size_t i = 0 ; i < Size ( ) ; i + + )
{
size_t ii = ( i * Size ( ) ) / Size ( ) ;
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 ;
}
}
/// <summary>
/// More advanced adjustment than MakeHueAdjustedPalette() provides.
/// Adjustments are applied in the order:
/// Frequency, index rotation, hue rotation, saturation, brightness, contrast, blur.
/// </summary>
/// <param name="palette">The palette to store the result in</param>
/// <param name="rot">Index rotation.</param>
/// <param name="hue">Hue rotation -5 - 5</param>
/// <param name="sat">Saturation 0 - 1</param>
/// <param name="bright">Brightness 0 - 1</param>
/// <param name="cont">Contrast -1 - 2</param>
/// <param name="blur">Blur 0 - 127</param>
/// <param name="freq">Frequency 1 - 10</param>
void MakeAdjustedPalette ( Palette < T > & palette , int rot , T hue , T sat , T bright , T cont , uint blur , uint freq )
{
T rgb [ 3 ] { } , hsv [ 3 ] { } ;
palette . m_Entries . resize ( Size ( ) ) ;
if ( freq > 1 )
{
const 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 ;
}
auto tempPal = palette ;
intmax_t iSize = intmax_t ( Size ( ) ) ;
for ( intmax_t i = 0 ; i < iSize ; i + + )
{
rgb [ 0 ] = tempPal [ std : : abs ( iSize + i - rot ) % iSize ] . r ; //Rotation.
rgb [ 1 ] = tempPal [ std : : abs ( iSize + i - rot ) % iSize ] . g ;
rgb [ 2 ] = tempPal [ std : : abs ( iSize + i - rot ) % iSize ] . b ;
RgbToHsv ( rgb , hsv ) ;
hsv [ 0 ] + = hue * T ( 6.0 ) ; //Hue.
hsv [ 1 ] = Clamp < T > ( hsv [ 1 ] + sat , 0 , 1 ) ; //Saturation.
HsvToRgb ( hsv , rgb ) ;
rgb [ 0 ] = Clamp < T > ( rgb [ 0 ] + bright , 0 , 1 ) ; //Brightness.
rgb [ 1 ] = Clamp < T > ( rgb [ 1 ] + bright , 0 , 1 ) ;
rgb [ 2 ] = Clamp < T > ( rgb [ 2 ] + bright , 0 , 1 ) ;
rgb [ 0 ] = Clamp < T > ( ( ( rgb [ 0 ] - T ( 0.5 ) ) * ( cont + T ( 1.0 ) ) ) + T ( 0.5 ) , 0 , 1 ) ; //Contrast.
rgb [ 1 ] = Clamp < T > ( ( ( rgb [ 1 ] - T ( 0.5 ) ) * ( cont + T ( 1.0 ) ) ) + T ( 0.5 ) , 0 , 1 ) ;
rgb [ 2 ] = Clamp < T > ( ( ( 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 )
{
tempPal = palette ;
for ( int i = 0 ; i < iSize ; 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 + + ;
auto k = ( iSize + j ) % iSize ;
if ( k ! = i )
{
rgb [ 0 ] = rgb [ 0 ] + tempPal [ k ] . r ;
rgb [ 1 ] = rgb [ 1 ] + tempPal [ k ] . g ;
rgb [ 2 ] = rgb [ 2 ] + tempPal [ k ] . b ;
}
}
if ( n ! = 0 )
{
palette [ i ] . r = rgb [ 0 ] / n ;
palette [ i ] . g = rgb [ 1 ] / n ;
palette [ i ] . b = rgb [ 2 ] / n ;
}
}
}
}
/// <summary>
/// Make a copy of this palette and multiply all RGB values by a scalar.
/// </summary>
/// <param name="palette">The palette to store the result in</param>
/// <param name="colorScalar">The color scalar to multiply each RGB value by</param>
template < typename bucketT >
void MakeDmap ( Palette < bucketT > & 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 ( size_t j = 0 ; j < palette . Size ( ) ; j + + )
{
palette . m_Entries [ j ] = m_Entries [ j ] * colorScalar ;
palette . m_Entries [ j ] . a = 1 ;
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="height">The height of the output block</param>
/// <returns>A vector holding the color values</returns>
vector < unsigned char > MakeRgbPaletteBlock ( size_t height )
{
const auto width = Size ( ) ;
vector < unsigned char > v ( height * width * 3 ) ;
if ( v . size ( ) = = ( height * Size ( ) * 3 ) )
{
for ( size_t i = 0 ; i < height ; i + + )
{
for ( size_t j = 0 ; j < width ; j + + )
{
v [ ( width * 3 * i ) + ( j * 3 ) ] = static_cast < unsigned char > ( m_Entries [ j ] [ 0 ] * static_cast < 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 ] = static_cast < unsigned char > ( m_Entries [ j ] [ 1 ] * static_cast < T > ( 255 ) ) ;
v [ ( width * 3 * i ) + ( j * 3 ) + 2 ] = static_cast < unsigned char > ( m_Entries [ j ] [ 2 ] * static_cast < T > ( 255 ) ) ;
}
}
}
return v ;
}
/// <summary>
/// Determine if a palette is all black.
/// </summary>
/// <returns>True if all colors are black, else false if at least one component of one color is non zero.</returns>
bool IsEmpty ( )
{
for ( glm : : length_t i = 0 ; i < Size ( ) ; i + + )
for ( glm : : length_t j = 0 ; j < 3 ; j + + )
if ( m_Entries [ i ] [ j ] ! = 0 )
return false ;
return true ;
}
/// <summary>
/// Convert RGB to HSV.
/// </summary>
/// <param name="r">Red 0 - 1</param>
/// <param name="g">Green 0 - 1</param>
/// <param name="b">Blue 0 - 1</param>
/// <param name="h">Hue 0 - 6</param>
/// <param name="s">Saturation 0 - 1</param>
/// <param name="v">Value 0 - 1</param>
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 ;
}
}
/// <summary>
/// Wrapper around RgbToHsv() which takes buffers as parameters instead of individual components.
/// </summary>
/// <param name="rgb">The RGB buffer</param>
/// <param name="hsv">The HSV buffer</param>
static void RgbToHsv ( const T * rgb , T * hsv )
{
RgbToHsv ( rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] , hsv [ 0 ] , hsv [ 1 ] , hsv [ 2 ] ) ;
}
/// <summary>
/// Convert HSV to RGB.
/// </summary>
/// <param name="h">Hue 0 - 6</param>
/// <param name="s">Saturation 0 - 1</param>
/// <param name="v">Value 0 - 1</param>
/// <param name="r">Red 0 - 1</param>
/// <param name="g">Green 0 - 1</param>
/// <param name="b">Blue 0 - 1</param>
static void HsvToRgb ( T h , T s , T v , T & r , T & g , T & b )
{
intmax_t j ;
T f , p , q , t ;
while ( h > = 6 )
h - = 6 ;
while ( h < 0 )
h + = 6 ;
j = Floor < T > ( 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 ;
}
}
/// <summary>
/// Wrapper around HsvToRgb() which takes buffers as parameters instead of individual components.
/// </summary>
/// <param name="hsv">The HSV buffer</param>
/// <param name="rgb">The RGB buffer</param>
static void HsvToRgb ( T * hsv , T * rgb )
{
HsvToRgb ( hsv [ 0 ] , hsv [ 1 ] , hsv [ 2 ] , rgb [ 0 ] , rgb [ 1 ] , rgb [ 2 ] ) ;
}
/// <summary>
/// Calculates the alpha.
/// Used for gamma correction in final accumulation.
/// Not the slightest clue what this is doing.
/// </summary>
/// <param name="density">Density</param>
/// <param name="gamma">Gamma</param>
/// <param name="linrange">Linear range</param>
/// <returns>Alpha</returns>
static T CalcAlpha ( T density , T gamma , T linrange )
{
T frac , alpha ;
T funcval = std : : pow ( linrange , gamma ) ;
if ( density > 0 )
{
if ( density < linrange )
{
frac = density / linrange ;
alpha = ( T ( 1.0 ) - frac ) * density * ( funcval / linrange ) + frac * std : : pow ( density , gamma ) ;
}
else
alpha = std : : pow ( density , gamma ) ;
}
else
alpha = 0 ;
return alpha ;
}
/// <summary>
/// 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.
/// </summary>
/// <param name="cBuf">The input RGB color buffer 0 - 1</param>
/// <param name="ls">Log scaling</param>
/// <param name="highPow">Highlight power, -1 - 1</param>
/// <param name="newRgb">Newly computed RGB value</param>
template < typename bucketT >
static void CalcNewRgb ( bucketT * cBuf , T ls , T highPow , bucketT * newRgb )
{
size_t rgbi ;
T lsratio ;
bucketT newhsv [ 3 ] ;
T maxa , maxc , newls ;
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 ;
newls = 1 / maxc ;
//If a channel is saturated and highlight power is non-negative
//modify the color to prevent hue shift.
if ( maxa > 1 & & highPow > = 0 )
{
lsratio = std : : pow ( newls / ls , highPow ) ;
//Calculate the max-value color (ranged 0 - 1).
for ( rgbi = 0 ; rgbi < 3 ; rgbi + + )
newRgb [ rgbi ] = bucketT ( newls ) * cBuf [ rgbi ] ;
//Reduce saturation by the lsratio.
Palette < bucketT > : : RgbToHsv ( newRgb , newhsv ) ;
newhsv [ 1 ] * = bucketT ( lsratio ) ;
Palette < bucketT > : : HsvToRgb ( newhsv , newRgb ) ;
}
else
{
adjustedHighlight = - highPow ;
if ( adjustedHighlight > 1 )
adjustedHighlight = 1 ;
if ( maxa < = 1 )
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 = - 1 ; //Index in the xml palette file of this palette, use -1 for random.
string m_Name = " - " ; //Name of this palette.
shared_ptr < string > m_Filename ; //Name of the parent file this palette came from, can be empty.
vector < v4T > m_Entries ;
map < T , v4T > m_SourceColors ;
} ;
}