2023-04-25 19:59:54 -04:00
# include "EmberPch.h"
# include "PaletteList.h"
# include "XmlToEmber.h"
namespace EmberNs
{
/// <summary>
/// Empty constructor which initializes the palette map with the default palette file.
/// </summary>
template < typename T >
PaletteList < T > : : PaletteList ( )
{
}
/// <summary>
/// Destructor which saves any modifiable palettes to file, just in case they were modified.
/// </summary>
template < typename T >
PaletteList < T > : : ~ PaletteList ( )
{
for ( auto & palFile : s_Palettes )
{
if ( IsModifiable ( palFile . first ) )
Save ( palFile . first ) ;
}
}
/// <summary>
/// Create a new palette file with the given name and vector of palettes, and save it.
/// </summary>
/// <param name="filename">The full path to the file to add</param>
/// <param name="palettes">The list of palettes which comprise the file</param>
/// <returns>True if the file did not exist, was successfully added and saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : AddPaletteFile ( const string & filename , const vector < Palette < T > > & palettes )
{
if ( ! GetPaletteListByFullPath ( filename ) )
{
s_Palettes . insert ( make_pair ( filename , palettes ) ) ;
Save ( filename ) ;
return true ;
}
return false ;
}
/// <summary>
/// Create an new empty palette file with the given name with a single modifiable palette in it.
/// </summary>
/// <param name="filename">The full path to the file to add</param>
/// <param name="palettes">The list of palettes which comprise the file</param>
/// <returns>True if the file did not exist, was successfully added and saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : AddEmptyPaletteFile ( const string & filename )
{
if ( ! GetPaletteListByFullPath ( filename ) )
{
const auto item = s_Palettes . insert ( make_pair ( filename , vector < Palette < T > > ( ) ) ) ;
Palette < T > p ;
p . m_Index = 0 ;
p . m_Name = " empty-default " ;
p . m_Filename = make_shared < string > ( filename ) ;
p . m_SourceColors = map < T , v4T >
{
{ T ( 0 ) , v4T ( T ( 0 ) , T ( 0 ) , T ( 0 ) , T ( 1 ) ) } ,
{ T ( 1 ) , v4T ( T ( 0 ) , T ( 0 ) , T ( 0 ) , T ( 1 ) ) }
} ;
item . first - > second . push_back ( p ) ;
Save ( filename ) ;
return true ;
}
return false ;
}
/// <summary>
/// Add a new palette to an existing palette file and save the file.
/// </summary>
/// <param name="filename">The full path to the existing palette file to add</param>
/// <param name="palette">The new palette to add to the file</param>
/// <returns>True if the palette file existed, the palette was added, and the file was successfully saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : AddPaletteToFile ( const string & filename , const Palette < T > & palette )
{
if ( const auto p = GetPaletteListByFullPathOrFilename ( filename ) )
{
p - > push_back ( palette ) ;
p - > back ( ) . m_Filename = make_shared < string > ( filename ) ; //Ensure the filename matches because this could have been duplicated from another palette file.
p - > back ( ) . m_Index = static_cast < int > ( p - > size ( ) ) - 1 ;
Save ( filename ) ;
return true ;
}
return false ;
}
/// <summary>
/// Replace an existing palette in a palette file with a new one and save the file.
/// The match is done based on palette name, so if there are duplicate names in
/// the file, only the first one will be replaced.
/// </summary>
/// <param name="filename">The full path to the existing palette file to replace a palette in</param>
/// <param name="palette">The new palette to use to replace an existing one in the file</param>
/// <returns>True if the palette file existed, the palette was replaced, and the file was successfully saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : Replace ( const string & filename , const Palette < T > & palette )
{
if ( const auto p = GetPaletteListByFullPathOrFilename ( filename ) )
{
for ( auto & pal : * p )
{
if ( pal . m_Name = = palette . m_Name )
{
const auto index = pal . m_Index ;
pal = palette ;
pal . m_Index = index ;
Save ( filename ) ;
return true ;
}
}
}
return false ;
}
/// <summary>
/// Replace an existing palette in a palette file with a new one and save the file.
/// The match is done based on the passed in index.
/// </summary>
/// <param name="filename">The full path to the existing palette file to replace a palette in</param>
/// <param name="palette">The new palette to use to replace an existing one in the file</param>
/// <param name="index">The 0-based index of the palette to replace</param>
/// <returns>True if the palette file existed, the palette was replaced, and the file was successfully saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : Replace ( const string & filename , const Palette < T > & palette , int index )
{
if ( const auto p = GetPaletteListByFullPathOrFilename ( filename ) )
{
if ( index < p - > size ( ) )
{
( * p ) [ index ] = palette ;
( * p ) [ index ] . m_Index = index ;
Save ( filename ) ;
return true ;
}
}
return false ;
}
/// <summary>
/// Delete an existing palette from a palette file.
/// The match is done based on the passed in index.
/// </summary>
/// <param name="filename">The full path to the existing palette file to delete a palette from</param>
/// <param name="index">The 0-based index of the palette to delete</param>
/// <returns>True if the palette file existed, the palette was deleted, and the file was successfully saved, else false.</returns>
template < typename T >
bool PaletteList < T > : : Delete ( const string & filename , int index )
{
int i = 0 ;
if ( const auto p = GetPaletteListByFullPathOrFilename ( filename ) )
{
if ( index < p - > size ( ) )
{
p - > erase ( p - > begin ( ) + index ) ;
for ( auto & pal : * p )
pal . m_Index = i + + ;
Save ( filename ) ;
return true ;
}
}
return false ;
}
/// <summary>
/// Read an Xml palette file into memory.
/// This must be called before any palette file usage.
/// </summary>
/// <param name="filename">The full path to the file to read</param>
/// <param name="force">If true, override the initialization state and force a read, else observe the initialization state.</param>
/// <returns>Whether anything was read</returns>
template < typename T >
bool PaletteList < T > : : Add ( const string & filename , bool force )
{
bool added = true ;
const auto contains = GetPaletteListByFullPathOrFilename ( filename ) ! = nullptr ;
const auto filenameonly = GetFilename ( filename ) ;
if ( contains & & ! force ) //Don't allow any palettes with the same name, even if they reside in different paths.
return false ;
const auto palettes = s_Palettes . insert ( make_pair ( filename , vector < Palette < T > > ( ) ) ) ;
if ( force | | palettes . second )
{
string buf ;
const char * loc = __FUNCTION__ ;
if ( ReadFile ( filename . c_str ( ) , buf ) )
{
const auto lower = ToLower ( filename ) ;
const auto pfilename = shared_ptr < string > ( new string ( filename ) ) ;
if ( EndsWith ( lower , " .xml " ) )
{
2024-05-08 09:31:55 -04:00
//Subtract 1 to make reading with nullterminate set to true work on linux.
2023-04-25 19:59:54 -04:00
const auto doc = xmlReadMemory ( static_cast < const char * > ( buf . data ( ) ) , static_cast < int > ( buf . size ( ) ) , filename . c_str ( ) , nullptr , XML_PARSE_NONET ) ;
if ( doc )
{
auto rootNode = xmlDocGetRootElement ( doc ) ;
if ( ! Compare ( rootNode - > name , " palettes " ) )
{
palettes . first - > second . clear ( ) ;
palettes . first - > second . reserve ( buf . size ( ) / 2048 ) ; //Roughly the size in bytes it takes to store the xml text of palette.
ParsePalettes ( rootNode , pfilename , palettes . first - > second ) ;
xmlFreeDoc ( doc ) ;
}
if ( palettes . first - > second . empty ( ) )
{
added = false ; //Reading failed, likely not a valid palette file.
s_Palettes . erase ( filename ) ;
AddToReport ( string ( loc ) + " : Couldn't parse xml doc " ) ;
}
}
else
{
added = false ;
s_Palettes . erase ( filename ) ;
AddToReport ( string ( loc ) + " : Couldn't load xml doc " ) ;
}
}
else if ( EndsWith ( lower , " .ugr " ) | | EndsWith ( lower , " .gradient " ) | | EndsWith ( lower , " .gradients " ) )
{
if ( ! ParsePalettes ( buf , pfilename , palettes . first - > second ) )
{
added = false ;
s_Palettes . erase ( filename ) ;
AddToReport ( string ( loc ) + " : Couldn't read palette file " + filename ) ;
}
}
}
else
{
added = false ;
s_Palettes . erase ( filename ) ;
AddToReport ( string ( loc ) + " : Couldn't read palette file " + filename ) ;
}
}
return added ;
}
/// <summary>
/// Get the palette at a random index in a random file in the map.
/// Attempt to avoid selecting a palette which is all black.
/// </summary>
/// <returns>A pointer to a random palette in a random file if successful, else nullptr.</returns>
template < typename T >
Palette < T > * PaletteList < T > : : GetRandomPalette ( )
{
size_t attempts = 0 ;
while ( attempts < Size ( ) * 10 )
{
auto p = s_Palettes . begin ( ) ;
const auto paletteFileIndex = QTIsaac < ISAAC_SIZE , ISAAC_INT > : : LockedRand ( Size ( ) ) ;
size_t i = 0 ;
//Move p forward i elements.
while ( i < paletteFileIndex & & p ! = s_Palettes . end ( ) )
{
+ + i ;
+ + p ;
}
if ( i < Size ( ) )
{
const size_t paletteIndex = QTIsaac < ISAAC_SIZE , ISAAC_INT > : : LockedRand ( p - > second . size ( ) ) ;
if ( paletteIndex < p - > second . size ( ) & & ! p - > second [ paletteIndex ] . IsEmpty ( ) )
return & p - > second [ paletteIndex ] ;
}
attempts + + ;
}
return Size ( ) ? ( & s_Palettes . begin ( ) - > second [ 0 ] ) : nullptr ;
}
/// <summary>
/// Get the palette at a specified index in the specified file in the map.
/// </summary>
/// <param name="filename">The filename of the palette to retrieve</param>
/// <param name="i">The index of the palette to read. A value of -1 indicates a random palette.</param>
/// <returns>A pointer to the requested palette if the index was in range, else nullptr.</returns>
template < typename T >
Palette < T > * PaletteList < T > : : GetPaletteByFilename ( const string & filename , size_t i )
{
if ( const auto palettes = GetPaletteListByFilename ( filename ) )
if ( i < palettes - > size ( ) )
return & ( * palettes ) [ i ] ;
return nullptr ;
}
/// <summary>
/// Get the palette at a specified index in the specified file in the map.
/// </summary>
/// <param name="filename">The full path and filename of the palette to retrieve</param>
/// <param name="i">The index of the palette to read. A value of -1 indicates a random palette.</param>
/// <returns>A pointer to the requested palette if the index was in range, else nullptr.</returns>
template < typename T >
Palette < T > * PaletteList < T > : : GetPaletteByFullPath ( const string & filename , size_t i )
{
if ( const auto palettes = GetPaletteListByFullPath ( filename ) )
if ( i < palettes - > size ( ) )
return & ( * palettes ) [ i ] ;
return nullptr ;
}
/// <summary>
/// Get a pointer to a palette with a specified name in the specified full path and filename in the map.
/// </summary>
/// <param name="filename">The filename of the palette to retrieve</param>
/// <param name="name">The name of the palette to retrieve</param>
/// <returns>A pointer to the requested palette if found, else nullptr.</returns>
template < typename T >
Palette < T > * PaletteList < T > : : GetPaletteByName ( const string & filename , const string & name )
{
if ( const auto palettes = GetPaletteListByFullPathOrFilename ( filename ) )
for ( auto & palette : * palettes )
if ( palette . m_Name = = name )
return & palette ;
return nullptr ;
}
/// <summary>
/// Get the palette file with the specified filename in the map.
/// </summary>
/// <param name="filename">The filename of the palette to retrieve</param>
/// <returns>A pointer to the requested palette if found, else nullptr.</returns>
template < typename T >
vector < Palette < T > > * PaletteList < T > : : GetPaletteListByFilename ( const string & filename )
{
const auto filenameonly = GetFilename ( filename ) ;
for ( auto & palettes : s_Palettes )
if ( GetFilename ( palettes . first ) = = filenameonly )
return & palettes . second ;
return nullptr ;
}
/// <summary>
/// Get the palette file with the specified full path and filename in the map.
/// </summary>
/// <param name="filename">The full path and filename of the palette to retrieve</param>
/// <returns>A pointer to the requested palette if found, else nullptr.</returns>
template < typename T >
vector < Palette < T > > * PaletteList < T > : : GetPaletteListByFullPath ( const string & filename )
{
const auto palettes = s_Palettes . find ( filename ) ;
if ( palettes ! = s_Palettes . end ( ) & & ! palettes - > second . empty ( ) )
return & palettes - > second ;
return nullptr ;
}
/// <summary>
/// Get the palette file with the specified full path and filename in the map.
/// If that does not work, try getting it with the filename alone.
/// </summary>
/// <param name="filename">The full path and filename or just the filename of the palette to retrieve</param>
/// <returns>A pointer to the requested palette if found, else nullptr.</returns>
template < typename T >
vector < Palette < T > > * PaletteList < T > : : GetPaletteListByFullPathOrFilename ( const string & filename )
{
auto p = GetPaletteListByFullPath ( filename ) ;
if ( ! p )
p = GetPaletteListByFilename ( filename ) ;
return p ;
}
/// <summary>
/// Get full path and filename of the pallete with the specified filename
/// </summary>
/// <param name="filename">The filename only of the palette to retrieve</param>
/// <returns>A pointer to the requested palette if found, else nullptr.</returns>
template < typename T >
string PaletteList < T > : : GetFullPathFromFilename ( const string & filename )
{
const auto filenameonly = GetFilename ( filename ) ;
for ( auto & palettes : s_Palettes )
if ( GetFilename ( palettes . first ) = = filenameonly )
return palettes . first ;
return " " ;
}
/// <summary>
/// Get a copy of the palette at a specified index in the specified file in the map
/// with its hue adjusted by the specified amount.
/// </summary>
/// <param name="filename">The filename of the palette to retrieve</param>
/// <param name="i">The index of the palette to read.</param>
/// <param name="hue">The hue adjustment to apply</param>
/// <param name="palette">The palette to store the output</param>
/// <returns>True if successful, else false.</returns>
template < typename T >
bool PaletteList < T > : : GetHueAdjustedPalette ( const string & filename , size_t i , T hue , Palette < T > & palette )
{
if ( const auto unadjustedPal = GetPaletteByFullPath ( filename , i ) )
{
unadjustedPal - > MakeHueAdjustedPalette ( palette , hue ) ;
return true ;
}
return false ;
}
/// <summary>
/// Clear the palette list and reset the initialization state.
/// </summary>
template < typename T >
void PaletteList < T > : : Clear ( )
{
s_Palettes . clear ( ) ;
}
/// <summary>
/// Get the size of the palettes map.
/// This will be the number of files read.
/// </summary>
/// <returns>The size of the palettes map</returns>
template < typename T >
size_t PaletteList < T > : : Size ( ) { return s_Palettes . size ( ) ; }
/// <summary>
/// Get the size of specified palette vector in the palettes map.
/// </summary>
/// <param name="index">The index of the palette in the map to retrieve</param>
/// <returns>The size of the palette vector at the specified index in the palettes map</returns>
template < typename T >
size_t PaletteList < T > : : Size ( size_t index )
{
size_t i = 0 ;
auto p = s_Palettes . begin ( ) ;
while ( i < index & & p ! = s_Palettes . end ( ) )
{
+ + i ;
+ + p ;
}
return p - > second . size ( ) ;
}
/// <summary>
/// Get the size of specified palette vector in the palettes map.
/// </summary>
/// <param name="s">The filename of the palette in the map to retrieve</param>
/// <returns>The size of the palette vector at the specified index in the palettes map</returns>
template < typename T >
size_t PaletteList < T > : : Size ( const string & s )
{
return s_Palettes [ s ] . size ( ) ;
}
/// <summary>
/// Get the name of specified palette in the palettes map.
/// </summary>
/// <param name="index">The index of the palette in the map to retrieve</param>
/// <returns>The name of the palette vector at the specified index in the palettes map</returns>
template < typename T >
const string & PaletteList < T > : : Name ( size_t index )
{
size_t i = 0 ;
auto p = s_Palettes . begin ( ) ;
while ( i < index & & p ! = s_Palettes . end ( ) )
{
+ + i ;
+ + p ;
}
return p - > first ;
}
/// <summary>
/// Determines whether all palettes in the passed in palette file are modifiable,
/// meaning whether the source colors have at least one element in them.
/// </summary>
/// <param name="filename">The full path to the existing palette file to search for a modifiable palette in</param>
/// <returns>True if at all palettes in the file were modifiable, else false.</returns>
template < typename T >
bool PaletteList < T > : : IsModifiable ( const string & filename )
{
if ( const auto palFile = GetPaletteListByFullPathOrFilename ( filename ) )
for ( auto & pal : * palFile )
if ( pal . m_SourceColors . empty ( ) )
return false ;
return true ;
}
/// <summary>
/// Get a const ref to the underlying static palette structure.
/// </summary>
/// <returns>s_Palettes</returns>
template < typename T >
const map < string , vector < Palette < T > > > & PaletteList < T > : : Palettes ( ) const
{
return s_Palettes ;
}
/// <summary>
/// Saves an existing file to disk.
/// </summary>
/// <param name="filename">The full path to the existing palette file to save</param>
/// <returns>True if successful, else false.</returns>
template < typename T >
bool PaletteList < T > : : Save ( const string & filename )
{
const auto fullpath = GetFullPathFromFilename ( filename ) ;
try
{
size_t index = 0 ;
ostringstream os ;
if ( const auto palFile = GetPaletteListByFullPathOrFilename ( filename ) )
{
ofstream f ( fullpath ) ;
os < < " <palettes> \n " ;
if ( f . is_open ( ) )
{
for ( auto & pal : * palFile )
{
os < < " <palette number= \" " < < index + + < < " \" name= \" " < < pal . m_Name < < " \" " ;
if ( ! pal . m_SourceColors . empty ( ) )
{
os < < " source_colors= \" " ;
for ( auto & sc : pal . m_SourceColors ) //Need to clamp these each from 0 to 1. Use our custom clamp funcs.//TODO
os < < Clamp < T > ( sc . first , 0 , 1 ) < < " , " < < Clamp < T > ( sc . second . r , 0 , 1 ) < < " , " < < Clamp < T > ( sc . second . g , 0 , 1 ) < < " , " < < Clamp < T > ( sc . second . b , 0 , 1 ) < < " " ;
os < < " \" " ;
}
os < < " data= \" " ;
for ( int i = 0 ; i < 32 ; i + + )
{
for ( int j = 0 ; j < 8 ; j + + )
{
const size_t idx = 8 * i + j ;
os < < " 00 " ;
os < < hex < < setw ( 2 ) < < setfill ( ' 0 ' ) < < static_cast < int > ( std : : rint ( pal [ idx ] [ 0 ] * 255 ) ) ;
os < < hex < < setw ( 2 ) < < setfill ( ' 0 ' ) < < static_cast < int > ( std : : rint ( pal [ idx ] [ 1 ] * 255 ) ) ;
os < < hex < < setw ( 2 ) < < setfill ( ' 0 ' ) < < static_cast < int > ( std : : rint ( pal [ idx ] [ 2 ] * 255 ) ) ;
}
os < < " \n " ;
}
os < < " \" /> \n " ;
}
}
os < < " </palettes> " ;
string s = os . str ( ) ;
f . write ( s . c_str ( ) , s . size ( ) ) ;
return true ;
}
}
catch ( const std : : exception & e )
{
cout < < " Error: Writing palette file " < < fullpath < < " failed: " < < e . what ( ) < < " \n " ;
return false ;
}
catch ( . . . )
{
cout < < " Error: Writing palette file " < < fullpath < < " failed. \n " ;
return false ;
}
return false ;
}
/// <summary>
/// Parses an Xml node for all palettes present and stores them in the passed in palette vector.
/// Note that although the Xml color values are expected to be 0-255, they are converted and
/// stored as normalized colors, with values from 0-1.
/// </summary>
/// <param name="node">The parent note of all palettes in the Xml file.</param>
/// <param name="filename">The name of the Xml file.</param>
/// <param name="palettes">The vector to store the parsed palettes associated with this file in.</param>
template < typename T >
void PaletteList < T > : : ParsePalettes ( xmlNode * node , const shared_ptr < string > & filename , vector < Palette < T > > & palettes )
{
char * val ;
xmlAttrPtr attr ;
int index = 0 ;
Locale lcl ; //This is required to properly read commas in the custom palette file. Because foreign locales treat a comma as the decimal point, which causes errors.
while ( node )
{
if ( node - > type = = XML_ELEMENT_NODE & & ! Compare ( node - > name , " palette " ) )
{
attr = node - > properties ;
Palette < T > palette ;
while ( attr )
{
val = reinterpret_cast < char * > ( xmlGetProp ( node , attr - > name ) ) ;
if ( ! Compare ( attr - > name , " data " ) )
{
string s1 , s ;
size_t tmp , colorCount = 0 ;
stringstream ss , temp ( val ) ; ss > > std : : hex ;
s . reserve ( 2048 ) ;
while ( temp > > s1 )
s + = s1 ;
auto length = s . size ( ) ;
for ( size_t strIndex = 0 ; strIndex < length ; )
{
strIndex + = 2 ; //Skip past the 00 at the beginning of each RGB.
for ( glm : : length_t i = 0 ; i < 3 & & colorCount < palette . Size ( ) ; i + + )
{
const char tmpStr [ 3 ] = { s [ strIndex + + ] , s [ strIndex + + ] , 0 } ; //Read out and convert the string two characters at a time.
ss . clear ( ) ; //Reset and fill the string stream.
ss . str ( tmpStr ) ;
ss > > tmp ; //Do the conversion.
palette . m_Entries [ colorCount ] [ i ] = static_cast < T > ( tmp ) / static_cast < T > ( 255 ) ; //Hex palette is [0..255], convert to [0..1].
}
colorCount + + ;
}
}
else if ( ! Compare ( attr - > name , " source_colors " ) )
{
const string s ( val ) ;
const auto vec1 = Split ( s , ' ' ) ;
for ( auto & v : vec1 )
{
const auto vec2 = Split ( v , ' , ' ) ;
if ( vec2 . size ( ) = = 4 )
{
float d1 = Clamp ( std : : stof ( vec2 [ 0 ] ) , 0.0f , 1.0f ) ;
palette . m_SourceColors [ d1 ] = v4F ( Clamp ( std : : stof ( vec2 [ 1 ] ) , 0.0f , 1.0f ) ,
Clamp ( std : : stof ( vec2 [ 2 ] ) , 0.0f , 1.0f ) ,
Clamp ( std : : stof ( vec2 [ 3 ] ) , 0.0f , 1.0f ) , 1.0f ) ;
}
}
}
else if ( ! Compare ( attr - > name , " name " ) )
{
palette . m_Name = string ( val ) ;
}
xmlFree ( val ) ;
attr = attr - > next ;
}
palette . m_Index = index + + ;
palette . m_Filename = filename ;
palettes . push_back ( palette ) ;
}
else
{
ParsePalettes ( node - > children , filename , palettes ) ;
}
node = node - > next ;
}
}
/// <summary>
/// Parses a gradient file for all palettes present and stores them in the passed in palette vector.
/// Note that although the Xml color values are expected to be 0-255, they are converted and
/// stored as normalized colors, with values from 0-1.
/// This format is from Ultra Fractal and Apophysis.
/// </summary>
/// <param name="buf">The data to parse.</param>
/// <param name="filename">The name of the gradient file.</param>
/// <param name="palettes">The vector to store the parsed palettes associated with this file in.</param>
/// <returns>True if at least one palette is read, else false.</returns>
template < typename T >
bool PaletteList < T > : : ParsePalettes ( const string & buf , const shared_ptr < string > & filename , vector < Palette < T > > & palettes )
{
int paletteIndex = 0 ;
size_t index = 0 ;
string line ;
string name ;
bool reading = false ;
bool found = false ;
istringstream iss ( buf ) ;
vector < string > splitVec ;
const char leftBrace = ' { ' ;
const char rightBrace = ' } ' ;
const string titleStr = " title= " ;
const string indexStr = " index= " ;
const string colorStr = " color= " ;
const string titleDelStr = " = \" " ;
const string colorDelStr = " = " ;
Palette < T > palette ;
Color < T > col ;
palettes . clear ( ) ;
while ( std : : getline ( iss , line ) )
{
if ( ! reading & & Contains ( line , leftBrace ) )
{
reading = true ;
}
else if ( Contains ( line , rightBrace ) )
{
if ( found )
palettes . push_back ( palette ) ;
reading = false ;
found = false ;
}
if ( reading )
{
if ( Find ( line , titleStr ) )
{
splitVec = Split ( line , titleDelStr , true ) ;
if ( splitVec . size ( ) > 2 )
name = splitVec [ 1 ] ;
}
else if ( Find ( line , indexStr ) & & Find ( line , colorStr ) )
{
if ( ! found )
{
index = 0 ;
found = true ;
palette . Clear ( ) ;
palette . m_Index = paletteIndex + + ;
palette . m_Name = name ;
palette . m_Filename = filename ;
}
splitVec = Split ( line , colorDelStr , true ) ;
if ( splitVec . size ( ) > 3 & & index < 256 )
{
int val = std : : stoi ( splitVec [ 3 ] ) ;
col . r = ( val & 0xFF ) / T ( 255 ) ; //Hex palette is [0..255], convert to [0..1].
col . g = ( ( val > > 8 ) & 0xFF ) / T ( 255 ) ;
col . b = ( ( val > > 16 ) & 0xFF ) / T ( 255 ) ;
palette [ index ] = col ;
}
index + + ;
}
}
}
return ! palettes . empty ( ) ;
}
template EMBER_API class PaletteList < float > ;
# ifdef DO_DOUBLE
template EMBER_API class PaletteList < double > ;
# endif
}