2019-10-06 19:15:53 +00:00
/*
* * gl_palmanager . cpp
* * Palette management
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2019 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
* *
*/
# include <memory>
# include "m_crc32.h"
# include "glbackend.h"
# include "baselayer.h"
# include "resourcefile.h"
2019-10-17 22:20:27 +00:00
# include "imagehelpers.h"
2019-11-05 22:35:38 +00:00
# include "v_font.h"
2019-10-06 19:15:53 +00:00
//===========================================================================
//
// The palette manager will contain all palettes being used for texture
// creation. It is also responsible for creating palette textures for indexed
// rendering.
//
//===========================================================================
PaletteManager : : ~ PaletteManager ( )
{
DeleteAll ( ) ;
}
//===========================================================================
//
//
//
//===========================================================================
void PaletteManager : : DeleteAll ( )
{
for ( auto & pal : palettes )
{
if ( pal . paltexture ) delete pal . paltexture ;
}
2019-10-07 23:08:08 +00:00
for ( auto & pal : palswaps )
{
if ( pal . swaptexture ) delete pal . swaptexture ;
}
2019-10-06 22:07:45 +00:00
if ( palswapTexture ) delete palswapTexture ;
palswapTexture = nullptr ;
2019-10-06 19:15:53 +00:00
palettes . Reset ( ) ;
palswaps . Reset ( ) ;
2019-10-07 23:08:08 +00:00
lastindex = ~ 0u ;
lastsindex = ~ 0u ;
2019-10-06 19:15:53 +00:00
memset ( palettemap , 0 , sizeof ( palettemap ) ) ;
memset ( palswapmap , 0 , sizeof ( palswapmap ) ) ;
2019-10-06 22:34:15 +00:00
memset ( addshade , 0 , sizeof ( addshade ) ) ;
memset ( mulshade , 0 , sizeof ( mulshade ) ) ;
numshades = 1 ;
2019-10-06 22:07:45 +00:00
2019-10-06 19:15:53 +00:00
}
//===========================================================================
//
// Adds a new palette while looking for duplicates.
//
//===========================================================================
unsigned PaletteManager : : FindPalette ( const uint8_t * paldata )
{
auto crc32 = CalcCRC32 ( paldata , 1024 ) ;
for ( unsigned int i = 0 ; i < palettes . Size ( ) ; i + + )
{
if ( crc32 = = palettes [ i ] . crc32 )
{
if ( ! memcmp ( paldata , palettes [ i ] . colors , 1024 ) )
{
return i ;
}
}
}
PaletteData pd ;
memcpy ( pd . colors , paldata , 1024 ) ;
pd . crc32 = crc32 ;
pd . paltexture = nullptr ;
2019-10-06 22:07:45 +00:00
pd . shadesdone = false ;
2019-10-06 19:15:53 +00:00
return palettes . Push ( pd ) ;
}
2019-10-06 22:07:45 +00:00
//===========================================================================
//
// Adds a new palette while looking for duplicates.
//
//===========================================================================
unsigned PaletteManager : : FindPalswap ( const uint8_t * paldata )
{
2019-10-07 23:37:43 +00:00
if ( paldata = = nullptr ) return 0 ;
2019-10-06 22:34:15 +00:00
auto crc32 = CalcCRC32 ( paldata , 256 * numshades ) ;
2019-10-06 22:07:45 +00:00
for ( unsigned int i = 0 ; i < palswaps . Size ( ) ; i + + )
{
if ( crc32 = = palswaps [ i ] . crc32 )
{
2019-10-06 22:34:15 +00:00
if ( ! memcmp ( paldata , palswaps [ i ] . lookup , 256 * numshades ) )
2019-10-06 22:07:45 +00:00
{
return i ;
}
}
}
PalswapData pd ;
2019-10-06 22:34:15 +00:00
pd . lookup = paldata ;
2019-10-06 22:07:45 +00:00
pd . crc32 = crc32 ;
2019-10-07 23:08:08 +00:00
pd . swaptexture = nullptr ;
2019-10-19 13:52:46 +00:00
// Find what index maps to black (or the darkest available color)
int found = - 1 ;
PalEntry foundColor = 0xffffffff ;
for ( int i = 0 ; i < 255 ; i + + )
{
int map = paldata [ i ] ;
PalEntry color = palettes [ 0 ] . colors [ map ] ;
if ( color . Luminance ( ) < foundColor . Luminance ( ) )
{
foundColor = color ;
found = i ;
}
}
// Determine the fade color. We pick what black, or the darkest color, maps to in the lowest shade level.
int map = paldata [ ( numshades - 2 ) * 256 + found ] ; // do not look in the latest shade level because it doesn't always contain useful data for this.
pd . fadeColor = palettes [ 0 ] . colors [ map ] ;
if ( pd . fadeColor . Luminance ( ) < 10 ) pd . fadeColor = 0 ; // Account for the inability to check the last fade level by using a higher threshold for determining black fog.
2019-10-06 22:07:45 +00:00
return palswaps . Push ( pd ) ;
}
2019-10-06 19:15:53 +00:00
//===========================================================================
//
//
//
//===========================================================================
2019-10-19 20:46:37 +00:00
void PaletteManager : : SetPalette ( int index , const uint8_t * data )
2019-10-06 19:15:53 +00:00
{
// New palettes may only be added if declared transient or on startup.
// Otherwise this would require a renderer reset to flush out the textures affected by the change.
if ( index < 0 | | index > 255 ) return ; // invalid index - ignore.
palettemap [ index ] = FindPalette ( data ) ;
2019-10-17 22:20:27 +00:00
if ( index = = 0 )
{
ImageHelpers : : SetPalette ( ( PalEntry * ) data ) ; // Palette 0 is always the reference for downconverting images
}
2019-10-06 19:15:53 +00:00
}
//===========================================================================
//
//
//
//===========================================================================
void PaletteManager : : BindPalette ( int index )
{
2019-10-19 20:46:37 +00:00
if ( palettemap [ index ] < palettes . Size ( ) )
2019-10-06 19:15:53 +00:00
{
auto uindex = palettemap [ index ] ;
if ( uindex ! = lastindex )
{
lastindex = uindex ;
if ( palettes [ uindex ] . paltexture = = nullptr )
{
auto p = GLInterface . NewTexture ( ) ;
2019-10-19 21:14:36 +00:00
p - > CreateTexture ( 256 , 1 , FHardwareTexture : : TrueColor , false ) ;
2019-10-19 08:21:07 +00:00
p - > LoadTexture ( ( uint8_t * ) palettes [ uindex ] . colors ) ;
2019-10-19 17:10:09 +00:00
p - > SetSampler ( SamplerNoFilterClampXY ) ;
2019-10-06 19:15:53 +00:00
palettes [ uindex ] . paltexture = p ;
}
inst - > BindTexture ( 2 , palettes [ uindex ] . paltexture ) ;
}
}
}
2019-10-06 22:07:45 +00:00
//===========================================================================
//
//
//
//===========================================================================
2019-10-06 22:34:15 +00:00
void PaletteManager : : SetPalswapData ( int index , const uint8_t * data , int numshades_ )
2019-10-06 22:07:45 +00:00
{
if ( index < 0 | | index > 255 ) return ; // invalid index - ignore.
2019-10-06 22:34:15 +00:00
numshades = numshades_ ;
2019-10-06 22:07:45 +00:00
palswapmap [ index ] = FindPalswap ( data ) ;
}
2019-10-06 19:15:53 +00:00
2019-10-06 22:34:15 +00:00
//===========================================================================
//
//
//
//===========================================================================
2019-10-07 23:08:08 +00:00
void PaletteManager : : BindPalswap ( int index )
2019-10-06 19:15:53 +00:00
{
2019-10-07 23:08:08 +00:00
if ( palswapmap [ index ] < palswaps . Size ( ) )
2019-10-06 22:07:45 +00:00
{
2019-10-07 23:08:08 +00:00
auto uindex = palswapmap [ index ] ;
if ( uindex ! = lastsindex )
{
lastsindex = uindex ;
2019-10-19 14:35:06 +00:00
auto & ps = palswaps [ uindex ] ;
if ( ps . swaptexture = = nullptr )
2019-10-07 23:08:08 +00:00
{
auto p = GLInterface . NewTexture ( ) ;
2019-10-19 21:14:36 +00:00
p - > CreateTexture ( 256 , numshades , FHardwareTexture : : Indexed , false ) ;
2019-10-19 14:35:06 +00:00
p - > LoadTexture ( ( uint8_t * ) ps . lookup ) ;
2019-10-19 17:10:09 +00:00
p - > SetSampler ( SamplerNoFilterClampXY ) ;
2019-10-19 14:35:06 +00:00
ps . swaptexture = p ;
2019-10-07 23:08:08 +00:00
}
2019-10-19 14:35:06 +00:00
inst - > BindTexture ( 1 , ps . swaptexture ) ;
inst - > SetFadeColor ( ps . fadeColor ) ;
2019-10-07 23:08:08 +00:00
}
2019-10-06 22:07:45 +00:00
}
}
2019-10-07 23:08:08 +00:00
2019-10-17 22:20:27 +00:00
2019-10-18 09:37:07 +00:00
int PaletteManager : : LookupPalette ( int palette , int palswap , bool brightmap )
2019-10-17 22:20:27 +00:00
{
int realpal = palettemap [ palette ] ;
int realswap = palswapmap [ palswap ] ;
2019-10-18 10:11:53 +00:00
int combined = ( brightmap ? 0x1000000 : 0 ) + realpal * 0x10000 + realswap ;
2019-10-17 22:20:27 +00:00
int * combinedindex = swappedpalmap . CheckKey ( combined ) ;
if ( combinedindex ) return * combinedindex ;
PaletteData * paldata = & palettes [ realpal ] ;
PalswapData * swapdata = & palswaps [ realswap ] ;
PalEntry swappedpalette [ 256 ] ;
2019-10-18 10:11:53 +00:00
if ( ! brightmap )
2019-10-17 22:20:27 +00:00
{
2019-10-18 10:11:53 +00:00
for ( int i = 0 ; i < 255 ; i + + )
{
int swapi = swapdata - > lookup [ i ] ;
swappedpalette [ i ] = paldata - > colors [ swapi ] ;
swappedpalette [ i ] . a = 255 ;
}
}
else
{
bool found = false ;
memset ( swappedpalette , 0 , sizeof ( swappedpalette ) ) ;
for ( int i = 0 ; i < 255 ; i + + )
{
int swapi = swapdata - > lookup [ i ] ;
auto swapc = paldata - > colors [ swapi ] ;
if ( swapc . a )
{
found = true ;
swappedpalette [ i ] = 0xffffffff ;
}
}
if ( ! found )
{
swappedpalmap . Insert ( combined , - 1 ) ;
return - 1 ;
}
2019-10-17 22:20:27 +00:00
}
2019-10-18 10:11:53 +00:00
swappedpalette [ 255 ] = 0 ;
2019-10-17 22:20:27 +00:00
int palid = FindPalette ( ( uint8_t * ) swappedpalette ) ;
swappedpalmap . Insert ( combined , palid ) ;
return palid ;
}