2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 1998 - 2000 , Matthes Bender
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
/* Textures used by the landscape */
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "landscape/C4Texture.h"
2009-05-08 13:28:41 +00:00
2016-04-03 18:07:56 +00:00
# include "c4group/C4Components.h"
2017-04-30 08:49:09 +00:00
# include "c4group/C4Group.h"
2016-04-03 18:07:56 +00:00
# include "landscape/C4Landscape.h"
2016-04-20 19:20:58 +00:00
# include "lib/C4Random.h"
2016-02-08 01:13:18 +00:00
# include "lib/StdColors.h"
2009-05-08 13:28:41 +00:00
C4Texture : : C4Texture ( )
2010-03-28 18:58:01 +00:00
{
2016-11-02 23:58:02 +00:00
Surface32 = nullptr ;
2010-04-10 12:24:38 +00:00
AvgColor = 0x00000000 ;
2016-11-02 23:58:02 +00:00
Next = nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Texture : : ~ C4Texture ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
delete Surface32 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4TexMapEntry : : C4TexMapEntry ( )
2017-05-07 11:50:00 +00:00
: iMaterialIndex ( MNone )
2010-03-28 18:58:01 +00:00
{
}
2009-05-08 13:28:41 +00:00
void C4TexMapEntry : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Material . Clear ( ) ; Texture . Clear ( ) ;
iMaterialIndex = MNone ;
2016-11-02 23:58:02 +00:00
pMaterial = nullptr ;
2009-05-08 13:28:41 +00:00
MatPattern . Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4TexMapEntry : : Create ( const char * szMaterial , const char * szTexture )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Clear previous data
Clear ( ) ;
// Save names
Material = szMaterial ; Texture = szTexture ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4TexMapEntry : : Init ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Find material
2009-06-05 18:46:03 +00:00
iMaterialIndex = : : MaterialMap . Get ( Material . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
if ( ! MatValid ( iMaterialIndex ) )
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Error initializing material %s-%s: Invalid material! " , Material . getData ( ) , Texture . getData ( ) ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-06-05 18:46:03 +00:00
pMaterial = & : : MaterialMap . Map [ iMaterialIndex ] ;
2009-05-08 13:28:41 +00:00
// Find texture
2011-08-20 00:25:08 +00:00
StdStrBuf FirstTexture ;
FirstTexture . CopyUntil ( Texture . getData ( ) , ' - ' ) ;
C4Texture * sfcTexture = : : TextureMap . GetTexture ( FirstTexture . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
if ( ! sfcTexture )
{
2011-08-20 00:25:08 +00:00
DebugLogF ( " Error initializing material %s-%s: Invalid texture! " , Material . getData ( ) , FirstTexture . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
Clear ( ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Get overlay properties
int32_t iOverlayType = pMaterial - > OverlayType ;
int32_t iZoom = 0 ;
if ( iOverlayType & C4MatOv_Exact ) iZoom = 1 ;
if ( iOverlayType & C4MatOv_HugeZoom ) iZoom = 4 ;
// Create pattern
2009-07-24 21:50:04 +00:00
MatPattern . Set ( sfcTexture - > Surface32 , iZoom ) ;
2009-05-08 13:28:41 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2017-05-07 11:50:00 +00:00
C4TextureMap : : C4TextureMap ( )
2010-03-28 18:58:01 +00:00
{
2015-09-05 01:49:36 +00:00
Order . reserve ( C4M_MaxTexIndex ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4TextureMap : : ~ C4TextureMap ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4TextureMap : : AddEntry ( BYTE byIndex , const char * szMaterial , const char * szTexture )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Security
2010-03-28 18:58:01 +00:00
if ( byIndex < = 0 | | byIndex > = C4M_MaxTexIndex )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Set entry and initialize
Entry [ byIndex ] . Create ( szMaterial , szTexture ) ;
2010-03-28 18:58:01 +00:00
if ( fInitialized )
{
if ( ! Entry [ byIndex ] . Init ( ) )
2009-05-08 13:28:41 +00:00
{
// Clear entry if it could not be initialized
Entry [ byIndex ] . Clear ( ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
// Landscape must be notified (new valid pixel clr)
2009-06-05 15:20:41 +00:00
: : Landscape . HandleTexMapUpdate ( ) ;
2010-03-27 16:05:02 +00:00
}
2015-08-10 04:34:43 +00:00
// Add last in order list
Order . push_back ( byIndex ) ;
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2011-10-03 14:06:41 +00:00
bool C4TextureMap : : AddTexture ( const char * szTexture , C4Surface * sfcSurface )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Texture * pTexture ;
if ( ! ( pTexture = new C4Texture ) ) return false ;
2012-09-05 20:51:25 +00:00
pTexture - > Name . Copy ( szTexture ) ;
2010-03-27 16:05:02 +00:00
pTexture - > Surface32 = sfcSurface ;
pTexture - > Next = FirstTexture ;
FirstTexture = pTexture ;
2010-04-10 12:24:38 +00:00
// Compute average texture color
2012-02-12 18:41:48 +00:00
if ( sfcSurface )
2010-04-10 12:24:38 +00:00
{
2012-02-12 18:41:48 +00:00
sfcSurface - > Lock ( ) ;
uint32_t avg_c [ 4 ] = { 0 , 0 , 0 , 0 } ;
for ( int32_t y = 0 ; y < sfcSurface - > Hgt ; + + y )
2010-04-10 12:24:38 +00:00
{
2012-02-12 18:41:48 +00:00
for ( int32_t x = 0 ; x < sfcSurface - > Wdt ; + + x )
{
DWORD c = sfcSurface - > GetPixDw ( x , y , false ) ;
avg_c [ 0 ] + = c & 0xff ;
avg_c [ 1 ] + = ( c > > 8 ) & 0xff ;
avg_c [ 2 ] + = ( c > > 16 ) & 0xff ;
avg_c [ 3 ] + = ( c > > 24 ) & 0xff ;
}
2010-04-10 12:24:38 +00:00
}
2012-02-12 18:41:48 +00:00
sfcSurface - > Unlock ( ) ;
double Size = sfcSurface - > Wdt * sfcSurface - > Hgt ;
avg_c [ 0 ] = static_cast < uint32_t > ( avg_c [ 0 ] / Size + 0.5 ) ;
avg_c [ 1 ] = static_cast < uint32_t > ( avg_c [ 1 ] / Size + 0.5 ) ;
avg_c [ 2 ] = static_cast < uint32_t > ( avg_c [ 2 ] / Size + 0.5 ) ;
avg_c [ 3 ] = static_cast < uint32_t > ( avg_c [ 3 ] / Size + 0.5 ) ;
2013-01-07 23:24:41 +00:00
pTexture - > SetAverageColor ( avg_c [ 0 ] | ( avg_c [ 1 ] < < 8 ) | ( avg_c [ 2 ] < < 16 ) | ( avg_c [ 3 ] < < 24 ) ) ;
2010-04-10 12:24:38 +00:00
}
2012-02-12 18:41:48 +00:00
else
{
2013-01-07 23:24:41 +00:00
pTexture - > SetAverageColor ( 0x00000000 ) ;
2010-04-10 12:24:38 +00:00
}
2012-02-12 18:41:48 +00:00
2010-03-27 16:05:02 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4TextureMap : : Clear ( )
2010-03-28 18:58:01 +00:00
{
for ( int32_t i = 1 ; i < C4M_MaxTexIndex ; i + + )
2009-05-08 13:28:41 +00:00
Entry [ i ] . Clear ( ) ;
2010-03-27 16:05:02 +00:00
C4Texture * ctex , * next2 ;
for ( ctex = FirstTexture ; ctex ; ctex = next2 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
next2 = ctex - > Next ;
delete ctex ;
2010-03-28 18:58:01 +00:00
}
2016-11-02 23:58:02 +00:00
FirstTexture = nullptr ;
2009-05-08 13:28:41 +00:00
fInitialized = false ;
2015-09-05 01:49:36 +00:00
fEntriesAdded = false ;
fOverloadMaterials = false ;
fOverloadTextures = false ;
2015-08-10 04:34:43 +00:00
Order . clear ( ) ;
Order . reserve ( C4M_MaxTexIndex ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4TextureMap : : LoadFlags ( C4Group & hGroup , const char * szEntryName , bool * pOverloadMaterials , bool * pOverloadTextures )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Load the file
StdStrBuf TexMap ;
2011-03-05 01:44:26 +00:00
if ( ! hGroup . LoadEntryString ( szEntryName , & TexMap ) )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// Reset flags
2010-03-28 18:58:01 +00:00
if ( pOverloadMaterials ) * pOverloadMaterials = false ;
if ( pOverloadTextures ) * pOverloadTextures = false ;
2009-05-08 13:28:41 +00:00
// Check if there are flags in there
2010-03-28 18:58:01 +00:00
for ( const char * pPos = TexMap . getData ( ) ; pPos & & * pPos ; pPos = SSearch ( pPos + 1 , " \n " ) )
{
2009-05-08 13:28:41 +00:00
// Go over newlines
2010-03-28 18:58:01 +00:00
while ( * pPos = = ' \r ' | | * pPos = = ' \n ' ) pPos + + ;
2009-05-08 13:28:41 +00:00
// Flag?
if ( pOverloadMaterials & & SEqual2 ( pPos , " OverloadMaterials " ) )
2009-08-15 18:50:32 +00:00
* pOverloadMaterials = true ;
2009-05-08 13:28:41 +00:00
if ( pOverloadTextures & & SEqual2 ( pPos , " OverloadTextures " ) )
2009-08-15 18:50:32 +00:00
* pOverloadTextures = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Done
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
int32_t C4TextureMap : : LoadMap ( C4Group & hGroup , const char * szEntryName , bool * pOverloadMaterials , bool * pOverloadTextures )
2010-03-28 18:58:01 +00:00
{
2016-07-21 17:47:46 +00:00
static std : : regex line_terminator ( " \r ? \n " , static_cast < std : : regex : : flag_type > ( std : : regex_constants : : optimize | std : : regex_constants : : ECMAScript ) ) ;
2014-03-25 17:26:51 +00:00
2010-03-27 16:05:02 +00:00
char * bpMap ;
2014-03-25 17:26:51 +00:00
size_t map_size ;
int32_t iTextures = 0 ;
2010-03-27 16:05:02 +00:00
// Load text file into memory
2014-03-25 17:26:51 +00:00
if ( ! hGroup . LoadEntry ( szEntryName , & bpMap , & map_size , 1 ) ) return 0 ;
char * begin = bpMap ;
char * end = begin + map_size ;
size_t line = 1 ; // Counter for error messages
2016-07-21 17:47:46 +00:00
for ( auto it = std : : cregex_token_iterator ( begin , end , line_terminator , - 1 ) ; it ! = std : : cregex_token_iterator ( ) ; + + it , + + line )
2014-03-25 17:26:51 +00:00
{
if ( it - > compare ( " OverloadMaterials " ) = = 0 )
2010-03-28 18:58:01 +00:00
{
2014-03-25 17:26:51 +00:00
fOverloadMaterials = true ;
if ( pOverloadMaterials )
* pOverloadMaterials = true ;
}
else if ( it - > compare ( " OverloadTextures " ) = = 0 )
{
fOverloadTextures = true ;
if ( pOverloadTextures )
* pOverloadTextures = true ;
}
else if ( it - > length ( ) = = 0 | | it - > first [ 0 ] = = ' # ' | | std : : all_of ( it - > first , it - > second , & isspace ) )
{
// Skip empty lines, comments, and all-whitespace lines
continue ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2014-03-25 17:26:51 +00:00
// This must be a texmap entry now
std : : string value ;
// Read index
unsigned long index ;
try
{
size_t separator ;
index = std : : stoul ( it - > str ( ) , & separator , 10 ) ;
if ( index > = C4M_MaxTexIndex )
throw std : : out_of_range ( " Texture index out of range " ) ;
value . assign ( it - > first + separator + 1 , it - > second ) ;
}
catch ( std : : invalid_argument & )
{
DebugLogF ( " TexMap line %u: Texture index is not numeric " , static_cast < unsigned > ( line ) ) ;
continue ;
}
catch ( std : : out_of_range & )
{
DebugLogF ( " TexMap line %u: Texture index is out of range " , static_cast < unsigned > ( line ) ) ;
continue ;
}
// Split material/texture combination
std : : string : : const_iterator separator = std : : find ( value . cbegin ( ) , value . cend ( ) , ' - ' ) ;
if ( separator = = value . cend ( ) )
{
2017-05-03 18:28:00 +00:00
DebugLogF ( R " (TexMap line %u: Texture name " % s " is invalid (missing " - " )) " , static_cast < unsigned > ( line ) , value . c_str ( ) ) ;
2014-03-25 17:26:51 +00:00
continue ;
}
std : : string material ( value . cbegin ( ) , separator ) ;
std : : string texture ( separator + 1 , value . cend ( ) ) ;
if ( AddEntry ( index , material . c_str ( ) , texture . c_str ( ) ) )
+ + iTextures ;
2010-03-28 18:58:01 +00:00
}
2014-03-25 17:26:51 +00:00
}
2010-03-27 16:05:02 +00:00
// Delete buffer, return entry count
delete [ ] bpMap ;
2009-05-08 13:28:41 +00:00
fEntriesAdded = false ;
2010-03-27 16:05:02 +00:00
return iTextures ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4TextureMap : : Init ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iRemoved = 0 ;
// Initialize texture mappings
int32_t i ;
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + )
if ( ! Entry [ i ] . isNull ( ) )
if ( ! Entry [ i ] . Init ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
LogF ( " Error in TextureMap initialization at entry %d " , ( int ) i ) ;
Entry [ i ] . Clear ( ) ;
iRemoved + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
fInitialized = true ;
return iRemoved ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4TextureMap : : SaveMap ( C4Group & hGroup , const char * szEntryName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// build file in memory
StdStrBuf sTexMapFile ;
// add desc
2019-02-19 14:28:12 +00:00
sTexMapFile . Append ( " # Automatically generated texture map \n " ) ;
sTexMapFile . Append ( " # Contains material-texture-combinations added at runtime \n " ) ;
2009-05-08 13:28:41 +00:00
// add overload-entries
2019-02-19 14:28:12 +00:00
if ( fOverloadMaterials ) sTexMapFile . Append ( " # Import materials from global file as well \n OverloadMaterials \n " ) ;
if ( fOverloadTextures ) sTexMapFile . Append ( " # Import textures from global file as well \n OverloadTextures \n " ) ;
sTexMapFile . Append ( " \n " ) ;
2009-05-08 13:28:41 +00:00
// add entries
2017-05-03 18:28:00 +00:00
for ( auto i : Order )
2015-08-10 04:34:43 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Entry [ i ] . isNull ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// compose line
2019-02-19 14:28:12 +00:00
sTexMapFile . AppendFormat ( " %d=%s-%s \n " , i , Entry [ i ] . GetMaterialName ( ) , Entry [ i ] . GetTextureName ( ) ) ;
2010-03-28 18:58:01 +00:00
}
2015-08-10 04:34:43 +00:00
}
2009-05-08 13:28:41 +00:00
// create new buffer allocated with new [], because C4Group cannot handle StdStrBuf-buffers
size_t iBufSize = sTexMapFile . getLength ( ) ;
BYTE * pBuf = new BYTE [ iBufSize ] ;
memcpy ( pBuf , sTexMapFile . getData ( ) , iBufSize ) ;
// add to group
bool fSuccess = ! ! hGroup . Add ( szEntryName , pBuf , iBufSize , false , true ) ;
if ( ! fSuccess ) delete [ ] pBuf ;
// done
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
int32_t C4TextureMap : : LoadTextures ( C4Group & hGroup , C4Group * OverloadFile )
2010-03-28 18:58:01 +00:00
{
2009-05-09 15:08:10 +00:00
int32_t texnum = 0 ;
2009-05-08 13:28:41 +00:00
// overload: load from other file
if ( OverloadFile ) texnum + = LoadTextures ( * OverloadFile ) ;
2009-05-09 15:08:10 +00:00
char texname [ 256 + 1 ] ;
2009-05-08 13:28:41 +00:00
C4Surface * ctex ;
2009-05-09 15:08:10 +00:00
size_t binlen ;
2011-05-23 23:12:19 +00:00
2009-05-08 13:28:41 +00:00
hGroup . ResetSearch ( ) ;
2009-05-09 15:08:10 +00:00
while ( hGroup . AccessNextEntry ( " * " , & binlen , texname ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// check if it already exists in the map
2015-10-09 04:11:53 +00:00
const char * base_filename = GetFilenameOnly ( texname ) ;
if ( GetTexture ( base_filename ) ) continue ;
2015-10-16 00:29:20 +00:00
// skip shape textures for now. Will be added later after all base textures have been loaded
if ( WildcardMatch ( " * " C4CFN_MaterialShapeFiles , texname ) ) continue ;
2015-10-09 04:11:53 +00:00
// create surface
2009-05-09 15:08:10 +00:00
ctex = new C4Surface ( ) ;
2015-09-19 01:10:39 +00:00
if ( ctex - > Read ( hGroup , GetExtension ( texname ) , C4SF_MipMap ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
SReplaceChar ( texname , ' . ' , 0 ) ;
2009-05-09 15:08:10 +00:00
if ( AddTexture ( texname , ctex ) ) texnum + + ;
2009-05-08 13:28:41 +00:00
else delete ctex ;
2010-03-28 18:58:01 +00:00
}
2009-05-09 15:08:10 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-09 15:08:10 +00:00
delete ctex ;
2009-05-08 13:28:41 +00:00
}
}
2011-05-23 23:12:19 +00:00
2015-10-16 00:29:20 +00:00
// Load texture shapes
hGroup . ResetSearch ( ) ;
while ( hGroup . AccessNextEntry ( " * " C4CFN_MaterialShapeFiles , & binlen , texname ) )
{
// get associated texture
StdStrBuf texname4shape ( texname , true ) ;
texname4shape . SetLength ( texname4shape . getLength ( ) - SLen ( C4CFN_MaterialShapeFiles ) ) ;
C4Texture * base_tex = GetTexture ( texname4shape . getData ( ) ) ;
if ( ! base_tex | | ! base_tex - > Surface32 )
{
LogF ( " ERROR: Texture shape %s not loaded because associated texture (%s) not found or invalid. " , hGroup . GetFullName ( ) . getData ( ) , texname4shape . getData ( ) ) ;
continue ;
}
std : : unique_ptr < C4TextureShape > shape ( new C4TextureShape ( ) ) ;
int32_t scaler_zoom = 4 ;
if ( ! shape - > Load ( hGroup , texname , base_tex - > Surface32 - > Wdt / scaler_zoom , base_tex - > Surface32 - > Hgt / scaler_zoom ) )
{
LogF ( " Error loading texture shape %s. " , hGroup . GetFullName ( ) . getData ( ) ) ;
continue ;
}
base_tex - > SetMaterialShape ( shape . release ( ) ) ;
}
2010-03-28 18:58:01 +00:00
return texnum ;
}
2009-05-08 13:28:41 +00:00
bool C4TextureMap : : HasTextures ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return hGroup . EntryCount ( C4CFN_PNGFiles ) | | hGroup . EntryCount ( C4CFN_BitmapFiles ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4TextureMap : : MoveIndex ( BYTE byOldIndex , BYTE byNewIndex )
2010-03-28 18:58:01 +00:00
{
2015-08-10 04:34:43 +00:00
if ( byNewIndex = = byOldIndex ) return ;
2009-05-08 13:28:41 +00:00
Entry [ byNewIndex ] = Entry [ byOldIndex ] ;
2015-08-10 04:34:43 +00:00
Entry [ byOldIndex ] . Clear ( ) ;
auto old_entry = std : : find_if ( Order . begin ( ) , Order . end ( ) ,
[ byOldIndex ] ( const int32_t & entry ) { return entry = = byOldIndex ; } ) ;
if ( old_entry ! = Order . end ( ) ) * old_entry = byNewIndex ;
2009-05-08 13:28:41 +00:00
fEntriesAdded = true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
int32_t C4TextureMap : : GetIndex ( const char * szMaterial , const char * szTexture , bool fAddIfNotExist , const char * szErrorIfFailed )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
BYTE byIndex ;
// Find existing
2009-05-08 13:28:41 +00:00
for ( byIndex = 1 ; byIndex < C4M_MaxTexIndex ; byIndex + + )
if ( ! Entry [ byIndex ] . isNull ( ) )
if ( SEqualNoCase ( Entry [ byIndex ] . GetMaterialName ( ) , szMaterial ) )
if ( ! szTexture | | SEqualNoCase ( Entry [ byIndex ] . GetTextureName ( ) , szTexture ) )
return byIndex ;
2010-03-27 16:05:02 +00:00
// Add new entry
if ( fAddIfNotExist )
for ( byIndex = 1 ; byIndex < C4M_MaxTexIndex ; byIndex + + )
if ( Entry [ byIndex ] . isNull ( ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( AddEntry ( byIndex , szMaterial , szTexture ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
fEntriesAdded = true ;
return byIndex ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
if ( szErrorIfFailed ) DebugLogF ( " Error getting MatTex %s-%s for %s from TextureMap: Init failed. " , szMaterial , szTexture , szErrorIfFailed ) ;
2010-03-27 16:05:02 +00:00
return 0 ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Else, fail
2009-05-08 13:28:41 +00:00
if ( szErrorIfFailed ) DebugLogF ( " Error getting MatTex %s-%s for %s from TextureMap: %s. " , szMaterial , szTexture , szErrorIfFailed , fAddIfNotExist ? " Map is full! " : " Entry not found. " ) ;
2010-03-27 16:05:02 +00:00
return 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
int32_t C4TextureMap : : GetIndexMatTex ( const char * szMaterialTexture , const char * szDefaultTexture , bool fAddIfNotExist , const char * szErrorIfFailed )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// split material/texture pair
StdStrBuf Material , Texture ;
Material . CopyUntil ( szMaterialTexture , ' - ' ) ;
Texture . Copy ( SSearch ( szMaterialTexture , " - " ) ) ;
// texture not given or invalid?
int32_t iMatTex = 0 ;
2010-03-28 18:58:01 +00:00
if ( Texture . getData ( ) )
if ( ( iMatTex = GetIndex ( Material . getData ( ) , Texture . getData ( ) , fAddIfNotExist ) ) )
2009-05-08 13:28:41 +00:00
return iMatTex ;
2010-03-28 18:58:01 +00:00
if ( szDefaultTexture )
if ( ( iMatTex = GetIndex ( Material . getData ( ) , szDefaultTexture , fAddIfNotExist ) ) )
2009-05-08 13:28:41 +00:00
return iMatTex ;
// search material
2009-06-05 18:46:03 +00:00
long iMaterial = : : MaterialMap . Get ( szMaterialTexture ) ;
2009-05-08 13:28:41 +00:00
if ( ! MatValid ( iMaterial ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( szErrorIfFailed ) DebugLogF ( " Error getting MatTex for %s: Invalid material " , szErrorIfFailed ) ;
return 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// return default map entry
2009-06-05 18:46:03 +00:00
return : : MaterialMap . Map [ iMaterial ] . DefaultMatTex ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Texture * C4TextureMap : : GetTexture ( const char * szTexture )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Texture * pTexture ;
for ( pTexture = FirstTexture ; pTexture ; pTexture = pTexture - > Next )
2012-09-05 20:51:25 +00:00
if ( SEqualNoCase ( pTexture - > Name . getData ( ) , szTexture ) )
2010-03-27 16:05:02 +00:00
return pTexture ;
2016-11-02 23:58:02 +00:00
return nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-23 23:12:19 +00:00
int32_t C4TextureMap : : GetTextureIndex ( const char * szName )
{
C4Texture * pTexture ;
int32_t i = 0 ;
for ( pTexture = FirstTexture ; pTexture ; pTexture = pTexture - > Next , i + + )
2012-09-05 20:51:25 +00:00
if ( SEqualNoCase ( pTexture - > Name . getData ( ) , szName ) )
2011-05-23 23:12:19 +00:00
return i ;
return - 1 ;
}
2009-05-08 13:28:41 +00:00
bool C4TextureMap : : CheckTexture ( const char * szTexture )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Texture * pTexture ;
for ( pTexture = FirstTexture ; pTexture ; pTexture = pTexture - > Next )
2012-09-05 20:51:25 +00:00
if ( SEqualNoCase ( pTexture - > Name . getData ( ) , szTexture ) )
2010-03-27 16:05:02 +00:00
return true ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const char * C4TextureMap : : GetTexture ( int32_t iIndex )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
C4Texture * pTexture ;
2009-05-08 13:28:41 +00:00
int32_t cindex ;
2010-03-27 16:05:02 +00:00
for ( pTexture = FirstTexture , cindex = 0 ; pTexture ; pTexture = pTexture - > Next , cindex + + )
2009-05-08 13:28:41 +00:00
if ( cindex = = iIndex )
2012-09-05 20:51:25 +00:00
return pTexture - > Name . getData ( ) ;
2016-11-02 23:58:02 +00:00
return nullptr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2015-07-08 01:17:40 +00:00
BYTE C4TextureMap : : DefaultBkgMatTex ( BYTE fg ) const
{
// For the given foreground index, find the default background index
// If fg is semisolid, this is tunnel.
// Otherwise it is fg itself, so that tunnel and background bricks
// stay the way they are.
int32_t iTex = PixCol2Tex ( fg ) ;
if ( ! iTex ) return fg ; // sky
// Get material-texture mapping
const C4TexMapEntry * pTex = GetEntry ( iTex ) ;
// Texmap entry does not exist
if ( ! pTex | | ! pTex - > GetMaterial ( ) ) return fg ;
if ( DensitySemiSolid ( pTex - > GetMaterial ( ) - > Density ) )
return Mat2PixColDefault ( MTunnel ) ;
return fg ;
}
2015-08-10 04:34:43 +00:00
void C4TextureMap : : RemoveEntry ( int32_t iIndex )
{
// remove entry from table and order vector
if ( Inside < int32_t > ( iIndex , 1 , C4M_MaxTexIndex - 1 ) )
{
Entry [ iIndex ] . Clear ( ) ;
auto last_entry = std : : remove_if ( Order . begin ( ) , Order . end ( ) ,
[ iIndex ] ( const int32_t & entry ) { return entry = = iIndex ; } ) ;
Order . erase ( last_entry , Order . end ( ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-08-15 22:45:27 +00:00
void C4TextureMap : : StoreMapPalette ( CStdPalette * Palette , C4MaterialMap & rMaterial )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Sky color
2012-08-15 22:45:27 +00:00
Palette - > Colors [ 0 ] = C4RGB ( 192 , 196 , 252 ) ;
2009-05-08 13:28:41 +00:00
// Material colors by texture map entries
2015-07-01 01:58:42 +00:00
bool fSet [ C4M_MaxTexIndex ] ;
2010-03-27 16:05:02 +00:00
ZeroMem ( & fSet , sizeof ( fSet ) ) ;
2009-05-08 13:28:41 +00:00
int32_t i ;
2017-04-01 18:10:44 +00:00
for ( i = 1 ; i < C4M_MaxTexIndex ; i + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Find material
2017-04-01 18:10:44 +00:00
DWORD dwPix ;
auto texture = GetTexture ( Entry [ i ] . GetTextureName ( ) ) ;
if ( texture )
dwPix = texture - > GetAverageColor ( ) ;
else
dwPix = Entry [ i ] . GetPattern ( ) . PatternClr ( 0 , 0 ) ;
2012-08-15 22:45:27 +00:00
Palette - > Colors [ i ] = dwPix ;
2015-07-01 01:58:42 +00:00
fSet [ i ] = true ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Crosscheck colors, change equal palette entries
2015-07-01 01:58:42 +00:00
for ( i = 0 ; i < C4M_MaxTexIndex ; i + + ) if ( fSet [ i ] )
2010-03-28 18:58:01 +00:00
for ( ; ; )
2010-03-27 16:05:02 +00:00
{
2010-03-28 18:58:01 +00:00
// search equal entry
int32_t j = 0 ;
2012-08-15 22:45:27 +00:00
for ( ; j < i ; j + + )
if ( fSet [ j ] & & Palette - > Colors [ i ] = = Palette - > Colors [ j ] )
2010-03-28 18:58:01 +00:00
break ;
// not found? ok then
if ( j > = i ) break ;
// change randomly
2012-08-15 22:45:27 +00:00
Palette - > Colors [ i ] = C4RGB (
2016-04-25 15:32:23 +00:00
UnsyncedRandom ( 2 ) ? GetRedValue ( Palette - > Colors [ i ] ) + 3 : GetRedValue ( Palette - > Colors [ i ] ) - 3 ,
UnsyncedRandom ( 2 ) ? GetGreenValue ( Palette - > Colors [ i ] ) + 3 : GetGreenValue ( Palette - > Colors [ i ] ) - 3 ,
UnsyncedRandom ( 2 ) ? GetBlueValue ( Palette - > Colors [ i ] ) + 3 : GetBlueValue ( Palette - > Colors [ i ] ) - 3 ) ;
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-06-05 15:09:54 +00:00
C4TextureMap TextureMap ;