2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2009-06-05 13:41:20 +00:00
* Copyright ( c ) 1998 - 2000 Matthes Bender
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2001 - 2008 , 2010 - 2011 Sven Eberhardt
* Copyright ( c ) 2002 , 2004 - 2008 , 2011 Peter Wortmann
* Copyright ( c ) 2006 - 2011 G ü nther Brammer
2010-12-23 00:01:24 +00:00
* Copyright ( c ) 2009 Armin Burgmeier
* Copyright ( c ) 2010 Benjamin Herr
* Copyright ( c ) 2010 Nicolas Hake
2011-09-01 14:58:52 +00:00
* Copyright ( c ) 2011 Tobias Zwick
2009-05-08 13:28:41 +00:00
* Copyright ( c ) 2001 - 2009 , RedWolf Design GmbH , http : //www.clonk.de
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk .
*
* Permission to use , copy , modify , and / or distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
* See isc_license . txt for full license and disclaimer .
*
* " Clonk " is a registered trademark of Matthes Bender .
* See clonk_trademark_license . txt for full license .
*/
/* Handles landscape and sky */
# include <C4Include.h>
# include <C4Landscape.h>
2011-01-19 22:52:46 +00:00
2009-05-08 13:28:41 +00:00
# include <C4SolidMask.h>
2009-06-12 18:52:21 +00:00
# include <C4Game.h>
2011-01-19 22:52:46 +00:00
# include <C4Group.h>
2009-05-08 13:28:41 +00:00
# include <C4Map.h>
# include <C4MapCreatorS2.h>
# include <C4SolidMask.h>
# include <C4Object.h>
# include <C4Physics.h>
# include <C4Random.h>
2011-01-19 22:52:46 +00:00
# include <C4Surface.h>
2009-05-08 13:28:41 +00:00
# include <C4ToolsDlg.h>
# include <C4Record.h>
# include <C4Material.h>
2009-06-05 18:12:43 +00:00
# include <C4GameMessage.h>
2009-05-08 13:28:41 +00:00
# include <C4Application.h>
2009-06-12 18:52:21 +00:00
# include <C4Log.h>
2009-05-08 13:28:41 +00:00
# include <C4Stat.h>
2009-06-05 18:00:23 +00:00
# include <C4MassMover.h>
# include <C4PXS.h>
2009-06-11 19:59:35 +00:00
# include <C4Weather.h>
2009-06-12 18:52:21 +00:00
# include <C4GraphicsResource.h>
# include <C4GraphicsSystem.h>
# include <C4Texture.h>
2009-06-15 22:06:37 +00:00
# include <C4Record.h>
2012-04-27 17:04:43 +00:00
# include <CSurface8.h>
2009-05-08 13:28:41 +00:00
# include <StdPNG.h>
2011-05-30 22:33:35 +00:00
# include <C4MaterialList.h>
2009-05-08 13:28:41 +00:00
C4Landscape : : C4Landscape ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Default ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4Landscape : : ~ C4Landscape ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++ Execute and display +++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
void C4Landscape : : Execute ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Landscape scan
2009-05-08 13:28:41 +00:00
if ( ! NoScan )
2010-03-27 16:05:02 +00:00
ExecuteScan ( ) ;
2009-05-08 13:28:41 +00:00
// move sky
Sky . Execute ( ) ;
2010-03-27 16:05:02 +00:00
// Side open scan
/*if (!::Game.iTick255)
2010-03-28 18:58:01 +00:00
if ( Game . C4S . LScape . AutoScanSideOpen )
ScanSideOpen ( ) ; */
2009-05-08 13:28:41 +00:00
# ifdef _DEBUG
2009-06-12 18:52:21 +00:00
/*if(!::Game.iTick255)
2010-03-28 18:58:01 +00:00
UpdatePixCnt ( C4Rect ( 0 , 0 , Width , Height ) , true ) ;
2009-06-12 18:52:21 +00:00
if ( ! : : Game . iTick255 )
2010-03-28 18:58:01 +00:00
{
DWORD MatCountCheck [ C4MaxMaterial ] , EffectiveMatCountCheck [ C4MaxMaterial ] ;
int32_t iMat ;
for ( iMat = 0 ; iMat < : : MaterialMap . Num ; iMat + + )
{
MatCountCheck [ iMat ] = MatCount [ iMat ] ;
EffectiveMatCountCheck [ iMat ] = EffectiveMatCount [ iMat ] ;
}
ClearMatCount ( ) ;
UpdateMatCnt ( C4Rect ( 0 , 0 , Width , Height ) , true ) ;
for ( iMat = 0 ; iMat < : : MaterialMap . Num ; iMat + + )
{
assert ( MatCount [ iMat ] = = MatCountCheck [ iMat ] ) ;
assert ( EffectiveMatCount [ iMat ] = = EffectiveMatCountCheck [ iMat ] ) ;
}
} */
2009-05-08 13:28:41 +00:00
# endif
// Relights
2010-03-27 16:05:02 +00:00
if ( ! : : Game . iTick35 )
2009-05-08 13:28:41 +00:00
DoRelights ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : ExecuteScan ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
int32_t cy , mat ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Check: Scan needed?
2009-06-11 19:59:35 +00:00
const int32_t iTemperature = : : Weather . GetTemperature ( ) ;
2010-03-28 18:58:01 +00:00
for ( mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
if ( MatCount [ mat ] )
{
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertTo & &
iTemperature < : : MaterialMap . Map [ mat ] . BelowTempConvert )
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
else if ( : : MaterialMap . Map [ mat ] . AboveTempConvertTo & &
iTemperature > : : MaterialMap . Map [ mat ] . AboveTempConvert )
2010-03-27 16:05:02 +00:00
break ;
2010-03-28 18:58:01 +00:00
}
if ( mat > = : : MaterialMap . Num )
2010-03-27 16:05:02 +00:00
return ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_MATSCAN
AddDbgRec ( RCT_MatScan , & ScanX , sizeof ( ScanX ) ) ;
# endif
2010-03-27 16:05:02 +00:00
for ( int32_t cnt = 0 ; cnt < ScanSpeed ; cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Scan landscape column: sectors down
2010-03-28 18:58:01 +00:00
int32_t last_mat = - 1 ;
2010-03-27 16:05:02 +00:00
for ( cy = 0 ; cy < Height ; cy + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
mat = _GetMat ( ScanX , cy ) ;
2010-03-28 18:58:01 +00:00
// material change?
if ( last_mat ! = mat )
{
// upwards
if ( last_mat ! = - 1 )
DoScan ( ScanX , cy - 1 , last_mat , 1 ) ;
// downwards
if ( mat ! = - 1 )
cy + = DoScan ( ScanX , cy , mat , 0 ) ;
}
last_mat = mat ;
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// Scan advance & rewind
ScanX + + ;
if ( ScanX > = Width )
ScanX = 0 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
# define PRETTY_TEMP_CONV
int32_t C4Landscape : : DoScan ( int32_t cx , int32_t cy , int32_t mat , int32_t dir )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t conv_to_tex = 0 ;
2009-06-11 19:59:35 +00:00
int32_t iTemperature = : : Weather . GetTemperature ( ) ;
2010-03-27 16:05:02 +00:00
// Check below conv
2010-03-28 18:58:01 +00:00
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertDir = = dir )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ mat ] . BelowTempConvertTo )
if ( iTemperature < : : MaterialMap . Map [ mat ] . BelowTempConvert )
conv_to_tex = : : MaterialMap . Map [ mat ] . BelowTempConvertTo ;
2010-03-27 16:05:02 +00:00
// Check above conv
2010-03-28 18:58:01 +00:00
if ( : : MaterialMap . Map [ mat ] . AboveTempConvertDir = = dir )
2009-06-05 18:46:03 +00:00
if ( : : MaterialMap . Map [ mat ] . AboveTempConvertTo )
if ( iTemperature > : : MaterialMap . Map [ mat ] . AboveTempConvert )
conv_to_tex = : : MaterialMap . Map [ mat ] . AboveTempConvertTo ;
2009-05-08 13:28:41 +00:00
// nothing to do?
if ( ! conv_to_tex ) return 0 ;
// find material
2009-06-05 15:09:54 +00:00
int32_t conv_to = : : TextureMap . GetEntry ( conv_to_tex ) - > GetMaterialIndex ( ) ;
2009-05-08 13:28:41 +00:00
// find mat top
2009-06-05 18:46:03 +00:00
int32_t mconv = : : MaterialMap . Map [ mat ] . TempConvStrength ,
2010-03-28 18:58:01 +00:00
mconvs = mconv ;
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC_MATSCAN
C4RCMatScan rc = { cx , cy , mat , conv_to , dir , mconvs } ;
AddDbgRec ( RCT_MatScanDo , & rc , sizeof ( C4RCMatScan ) ) ;
# endif
int32_t ydir = ( dir = = 0 ? + 1 : - 1 ) , cy2 ;
# ifdef PRETTY_TEMP_CONV
// get left pixel
int32_t lmat = ( cx > 0 ? _GetMat ( cx - 1 , cy ) : - 1 ) ;
// left pixel not converted? do nothing
2010-03-28 18:58:01 +00:00
if ( lmat = = mat ) return 0 ;
2009-05-08 13:28:41 +00:00
// left pixel converted? suppose it was done by a prior scan and skip check
2010-03-28 18:58:01 +00:00
if ( lmat ! = conv_to )
2009-05-08 13:28:41 +00:00
{
int32_t iSearchRange = Max < int32_t > ( 5 , mconvs ) ;
// search upper/lower bound
int32_t cys = cy , cxs = cx ;
2010-03-28 18:58:01 +00:00
while ( cxs < GBackWdt - 1 )
2009-05-08 13:28:41 +00:00
{
// one step right
cxs + + ;
2010-03-28 18:58:01 +00:00
if ( _GetMat ( cxs , cys ) = = mat )
2009-05-08 13:28:41 +00:00
{
// search surface
cys - = ydir ;
2010-03-28 18:58:01 +00:00
while ( Inside < int32_t > ( cys , 0 , GBackHgt - 1 ) & & _GetMat ( cxs , cys ) = = mat )
2009-05-08 13:28:41 +00:00
{
cys - = ydir ;
2010-03-28 18:58:01 +00:00
if ( ( mconvs = Min ( mconv - Abs ( cys - cy ) , mconvs ) ) < 0 )
2009-05-08 13:28:41 +00:00
return 0 ;
}
// out of bounds?
2010-03-28 18:58:01 +00:00
if ( ! Inside < int32_t > ( cys , 0 , GBackHgt - 1 ) ) break ;
2009-05-08 13:28:41 +00:00
// back one step
cys + = ydir ;
}
else
{
// search surface
cys + = ydir ;
2010-03-28 18:58:01 +00:00
while ( Inside < int32_t > ( cys , 0 , GBackHgt - 1 ) & & _GetMat ( cxs , cys ) ! = mat )
2009-05-08 13:28:41 +00:00
{
cys + = ydir ;
2010-03-28 18:58:01 +00:00
if ( Abs ( cys - cy ) > iSearchRange )
2009-05-08 13:28:41 +00:00
break ;
}
// out of bounds?
2010-03-28 18:58:01 +00:00
if ( ! Inside < int32_t > ( cys , 0 , GBackHgt - 1 ) ) break ;
if ( Abs ( cys - cy ) > iSearchRange ) break ;
2009-05-08 13:28:41 +00:00
}
}
}
# endif
// Conversion
2010-03-28 18:58:01 +00:00
for ( cy2 = cy ; mconvs > = 0 & & Inside < int32_t > ( cy2 , 0 , GBackHgt - 1 ) ; cy2 + = ydir , mconvs - - )
{
2009-05-08 13:28:41 +00:00
// material changed?
int32_t pix = _GetPix ( cx , cy2 ) ;
2010-03-28 18:58:01 +00:00
if ( PixCol2Mat ( pix ) ! = mat ) break ;
2009-05-08 13:28:41 +00:00
# ifdef PRETTY_TEMP_CONV
// get left pixel
int32_t lmat = ( cx > 0 ? _GetMat ( cx - 1 , cy2 ) : - 1 ) ;
// left pixel not converted? break
2010-03-28 18:58:01 +00:00
if ( lmat = = mat ) break ;
2009-05-08 13:28:41 +00:00
# endif
// set mat
SBackPix ( cx , cy2 , MatTex2PixCol ( conv_to_tex ) + PixColIFT ( pix ) ) ;
CheckInstabilityRange ( cx , cy2 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// return pixel converted
return Abs ( cy2 - cy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : ScanSideOpen ( )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cy ;
for ( cy = 0 ; ( cy < Height ) & & ! GetPix ( 0 , cy ) ; cy + + ) { }
LeftOpen = cy ;
for ( cy = 0 ; ( cy < Height ) & & ! GetPix ( Width - 1 , cy ) ; cy + + ) { }
RightOpen = cy ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
2009-05-08 13:28:41 +00:00
void C4Landscape : : Draw ( C4TargetFacet & cgo , int32_t iPlayer )
2010-03-28 18:58:01 +00:00
{
2011-10-03 14:30:18 +00:00
if ( Modulation ) pDraw - > ActivateBlitModulation ( Modulation ) ;
2009-05-08 13:28:41 +00:00
// blit landscape
2009-06-05 15:14:20 +00:00
if ( : : GraphicsSystem . ShowSolidMask )
2011-10-03 14:30:18 +00:00
pDraw - > Blit8Fast ( Surface8 , cgo . TargetX , cgo . TargetY , cgo . Surface , cgo . X , cgo . Y , cgo . Wdt , cgo . Hgt ) ;
2011-05-23 23:12:19 +00:00
else if ( pLandscapeRender )
2010-03-28 18:58:01 +00:00
{
2011-05-23 23:12:19 +00:00
DoRelights ( ) ;
pLandscapeRender - > Draw ( cgo ) ;
2009-05-08 13:28:41 +00:00
}
2011-10-03 14:30:18 +00:00
if ( Modulation ) pDraw - > DeactivateBlitModulation ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : DoRelights ( )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
if ( ! pLandscapeRender ) return true ;
for ( int32_t i = 0 ; i < C4LS_MaxRelights ; i + + )
2009-05-08 13:28:41 +00:00
{
2011-05-31 01:04:38 +00:00
if ( ! Relights [ i ] . Wdt )
break ;
// Remove all solid masks in the (twice!) extended region around the change
C4Rect SolidMaskRect = pLandscapeRender - > GetAffectedRect ( Relights [ i ] ) ;
C4SolidMask * pSolid ;
for ( pSolid = C4SolidMask : : Last ; pSolid ; pSolid = pSolid - > Prev )
pSolid - > RemoveTemporary ( SolidMaskRect ) ;
// Perform the update
pLandscapeRender - > Update ( Relights [ i ] , this ) ;
// Restore Solidmasks
for ( pSolid = C4SolidMask : : First ; pSolid ; pSolid = pSolid - > Next )
pSolid - > PutTemporary ( SolidMaskRect ) ;
C4SolidMask : : CheckConsistency ( ) ;
// Clear slot
Relights [ i ] . Default ( ) ;
2009-05-08 13:28:41 +00:00
}
2011-05-31 01:04:38 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++ Add and destroy landscape++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > C4Landscape : : GetRoundPolygon ( int32_t x , int32_t y , int32_t size , int32_t smoothness ) const
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
/*
So what is this ? It ' s basically a circle with the radius ' size ' . The radius
is adjusted by two sin / cos waves . The random lies in the phase of the sin / cos
and in the factor the wave is added to the normal circle shape . smoothness from
0 to 100. 0 gives an exagerated ' explosion ' shape while 100 is almost a circle
*/
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( smoothness > 100 ) smoothness = 100 ;
if ( smoothness < 0 ) smoothness = 0 ;
if ( size < = 0 ) size = 1 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// vertex count of the polygon
int32_t count = 2 * size / 3 + 6 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > vertices ;
vertices . reserve ( count * 2 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// varying phase of the sin/cos waves
C4Real begin = itofix ( 360 ) * Random ( 100 ) / 100 ;
C4Real begin2 = itofix ( 360 ) * Random ( 100 ) / 100 ;
// parameters:
// the bigger the factor, the smaller the divergence from a circle
C4Real anticircle = itofix ( 3 ) + smoothness / 16 * smoothness / 16 ;
// the bigger the factor the more random is the divergence from the circle
int random = 80 * ( 200 - smoothness ) ;
for ( int i = 0 ; i < count ; + + i )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
C4Real angle = itofix ( 360 ) * i / count ;
C4Real currsize = itofix ( size ) ;
currsize + = Sin ( angle * 3 + begin + itofix ( Random ( random ) ) / 100 ) * size / anticircle ; // +sin
currsize + = Cos ( angle * 5 + begin2 + itofix ( Random ( random ) ) / 100 ) * size / anticircle / 2 ; // +cos
vertices . push_back ( x + fixtoi ( Sin ( angle ) * currsize ) ) ;
vertices . push_back ( y - fixtoi ( Cos ( angle ) * currsize ) ) ;
2009-05-08 13:28:41 +00:00
}
2011-05-31 01:04:38 +00:00
return vertices ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > C4Landscape : : GetRectangle ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt ) const
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > vertices ;
vertices . resize ( 8 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
vertices [ 0 ] = tx ; vertices [ 1 ] = ty ;
vertices [ 2 ] = tx ; vertices [ 3 ] = ty + hgt ;
vertices [ 4 ] = tx + wdt ; vertices [ 5 ] = ty + hgt ;
vertices [ 6 ] = tx + wdt ; vertices [ 7 ] = ty ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
return vertices ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ClearFreeRect ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
std : : vector < int32_t > vertices ( GetRectangle ( tx , ty , wdt , hgt ) ) ;
ForPolygon ( & vertices [ 0 ] , vertices . size ( ) / 2 , & C4Landscape : : ClearPix ) ;
}
2009-05-08 13:28:41 +00:00
2012-04-05 15:49:47 +00:00
int32_t C4Landscape : : DigFreeRect ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , C4Object * by_object , bool no_dig2objects )
2011-05-31 01:04:38 +00:00
{
std : : vector < int32_t > vertices ( GetRectangle ( tx , ty , wdt , hgt ) ) ;
2012-04-05 15:49:47 +00:00
return DigFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , no_dig2objects ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2012-04-05 15:49:47 +00:00
int32_t C4Landscape : : DigFree ( int32_t tx , int32_t ty , int32_t rad , C4Object * by_object , bool no_dig2objects )
2011-05-31 01:04:38 +00:00
{
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 80 ) ) ;
2012-04-05 15:49:47 +00:00
return DigFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , no_dig2objects ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : BlastFree ( int32_t tx , int32_t ty , int32_t rad , int32_t caused_by , C4Object * by_object )
{
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 30 ) ) ;
BlastFreeShape ( & vertices [ 0 ] , vertices . size ( ) , by_object , caused_by ) ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ShakeFree ( int32_t tx , int32_t ty , int32_t rad )
{
std : : vector < int32_t > vertices ( GetRoundPolygon ( tx , ty , rad , 50 ) ) ;
ForPolygon ( & vertices [ 0 ] , vertices . size ( ) / 2 , & C4Landscape : : ShakeFreePix ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-04-05 15:49:47 +00:00
int32_t C4Landscape : : DigFreeShape ( int * vtcs , int length , C4Object * by_object , bool no_dig2objects )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2012-04-05 01:59:45 +00:00
int32_t amount ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( by_object )
{
if ( ! by_object - > MaterialContents )
by_object - > MaterialContents = new C4MaterialList ;
2012-04-05 01:59:45 +00:00
amount = ForPolygon ( vtcs , length / 2 , & C4Landscape : : DigFreePix , by_object - > MaterialContents ) ;
2011-05-31 01:04:38 +00:00
}
else
2012-04-05 01:59:45 +00:00
amount = ForPolygon ( vtcs , length / 2 , & C4Landscape : : DigFreePix , NULL ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// create objects from the material
if ( ! : : Game . iTick5 )
{
2012-04-05 15:49:47 +00:00
if ( ! no_dig2objects )
if ( by_object )
if ( by_object - > MaterialContents )
{
int32_t tx = BoundingBox . GetMiddleX ( ) , ty = BoundingBox . GetBottom ( ) ;
DigMaterial2Objects ( tx , ty , by_object - > MaterialContents , by_object ) ;
}
2011-05-31 01:04:38 +00:00
}
2012-04-05 01:59:45 +00:00
return amount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : BlastFreeShape ( int * vtcs , int length , C4Object * by_object , int32_t by_player )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
C4MaterialList * MaterialContents = NULL ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( by_object )
{
if ( ! by_object - > MaterialContents )
by_object - > MaterialContents = new C4MaterialList ;
ForPolygon ( vtcs , length / 2 , & C4Landscape : : BlastFreePix , by_object - > MaterialContents ) ;
}
else
{
MaterialContents = new C4MaterialList ;
ForPolygon ( vtcs , length / 2 , & C4Landscape : : BlastFreePix , MaterialContents ) ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// create objects from the material
C4MaterialList * mat_list = NULL ;
if ( by_object )
mat_list = by_object - > MaterialContents ;
else
mat_list = MaterialContents ;
int32_t tx = BoundingBox . GetMiddleX ( ) , ty = BoundingBox . GetMiddleY ( ) ;
BlastMaterial2Objects ( tx , ty , mat_list , by_player , ( BoundingBox . Wdt + BoundingBox . Hgt ) / 4 ) ;
if ( MaterialContents ) delete MaterialContents ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : BlastMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , int32_t caused_by , int32_t str )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
for ( int32_t mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
{
if ( mat_list - > Amount [ mat ] )
{
int32_t cast_strength = str ;
int32_t pxsamount = 0 , blastamount = 0 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( : : MaterialMap . Map [ mat ] . Blast2PXSRatio ! = 0 )
{
pxsamount = mat_list - > Amount [ mat ] / : : MaterialMap . Map [ mat ] . Blast2PXSRatio ;
: : PXS . Cast ( mat , pxsamount , tx , ty , cast_strength * 2 ) ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
if ( : : MaterialMap . Map [ mat ] . Blast2Object ! = C4ID : : None )
{
if ( : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ! = 0 )
{
blastamount = mat_list - > Amount [ mat ] / : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ;
Game . CastObjects ( : : MaterialMap . Map [ mat ] . Blast2Object , NULL , blastamount , cast_strength , tx , ty , NO_OWNER , caused_by ) ;
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
mat_list - > Amount [ mat ] - = Max ( blastamount * : : MaterialMap . Map [ mat ] . Blast2ObjectRatio ,
pxsamount * : : MaterialMap . Map [ mat ] . Blast2PXSRatio ) ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-08-20 14:43:58 +00:00
void C4Landscape : : DigMaterial2Objects ( int32_t tx , int32_t ty , C4MaterialList * mat_list , C4Object * pCollect )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
for ( int32_t mat = 0 ; mat < : : MaterialMap . Num ; mat + + )
{
if ( mat_list - > Amount [ mat ] )
{
if ( : : MaterialMap . Map [ mat ] . Dig2Object ! = C4ID : : None )
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ! = 0 )
2011-08-20 14:43:58 +00:00
while ( mat_list - > Amount [ mat ] > = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio )
2011-05-31 01:04:38 +00:00
{
2011-08-20 14:43:58 +00:00
C4Object * pObj = Game . CreateObject ( : : MaterialMap . Map [ mat ] . Dig2Object , NULL , NO_OWNER , tx , ty ) ;
// Try to collect object
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectCollect & & pCollect & & pObj )
if ( ! pCollect - > Collect ( pObj ) )
// Collection forced? Don't generate objects
if ( : : MaterialMap . Map [ mat ] . Dig2ObjectCollect = = 2 )
{
pObj - > AssignRemoval ( ) ;
2012-01-21 17:33:00 +00:00
// Cap so we never have more than one object ´ worth of material in the store
mat_list - > Amount [ mat ] = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ;
2011-10-10 19:25:35 +00:00
break ;
2011-08-20 14:43:58 +00:00
}
mat_list - > Amount [ mat ] - = : : MaterialMap . Map [ mat ] . Dig2ObjectRatio ;
2011-05-31 01:04:38 +00:00
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : DigFreePix ( int32_t tx , int32_t ty )
2011-01-19 22:52:46 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t mat = GetMat ( tx , ty ) ;
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . DigFree )
{
ClearPix ( tx , ty ) ;
// check for instable materials to start moving by the cleared space
CheckInstabilityRange ( tx , ty ) ;
return true ;
}
return false ;
2011-01-19 22:52:46 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : BlastFreePix ( int32_t tx , int32_t ty )
2011-01-19 22:52:46 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t mat = GetMat ( tx , ty ) ;
if ( MatValid ( mat ) )
{
// for blast, either shift to different material or blast free
if ( : : MaterialMap . Map [ mat ] . BlastFree )
{
ClearPix ( tx , ty ) ;
// check for instable materials to start moving by the cleared space
CheckInstabilityRange ( tx , ty ) ;
return true ;
}
else
if ( : : MaterialMap . Map [ mat ] . BlastShiftTo )
SetPix ( tx , ty , MatTex2PixCol ( : : MaterialMap . Map [ mat ] . BlastShiftTo ) + GBackIFT ( tx , ty ) ) ;
}
return false ;
}
bool C4Landscape : : ShakeFreePix ( int32_t tx , int32_t ty )
{
int32_t mat = GetMat ( tx , ty ) ;
if ( MatValid ( mat ) )
{
if ( : : MaterialMap . Map [ mat ] . DigFree )
{
ClearPix ( tx , ty ) ;
: : PXS . Create ( mat , itofix ( tx ) , itofix ( ty ) ) ;
// check for instable materials to start moving by the cleared space
CheckInstabilityRange ( tx , ty ) ;
return true ;
}
}
return false ;
2011-01-19 22:52:46 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : ClearPix ( int32_t tx , int32_t ty )
{
BYTE bcol ;
if ( GBackIFT ( tx , ty ) )
bcol = Mat2PixColDefault ( MTunnel ) + IFT ;
else
bcol = 0 ;
return SetPix ( tx , ty , bcol ) ;
}
2009-08-15 18:50:32 +00:00
bool C4Landscape : : SetPix ( int32_t x , int32_t y , BYTE npix )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC
C4RCSetPix rc ;
rc . x = x ; rc . y = y ; rc . clr = npix ;
AddDbgRec ( RCT_SetPix , & rc , sizeof ( rc ) ) ;
# endif
// check bounds
2010-03-28 18:58:01 +00:00
if ( x < 0 | | y < 0 | | x > = Width | | y > = Height )
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
// no change?
2010-03-28 18:58:01 +00:00
if ( npix = = _GetPix ( x , y ) )
2009-08-15 18:50:32 +00:00
return true ;
2009-05-08 13:28:41 +00:00
// note for relight
2011-05-23 23:12:19 +00:00
if ( pLandscapeRender )
{
C4Rect CheckRect = pLandscapeRender - > GetAffectedRect ( C4Rect ( x , y , 1 , 1 ) ) ;
for ( int32_t i = 0 ; i < C4LS_MaxRelights ; i + + )
if ( ! Relights [ i ] . Wdt | | Relights [ i ] . Overlap ( CheckRect ) | | i + 1 > = C4LS_MaxRelights )
{
Relights [ i ] . Add ( CheckRect ) ;
break ;
}
}
2009-05-08 13:28:41 +00:00
// set pixel
return _SetPix ( x , y , npix ) ;
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 C4Landscape : : _SetPix ( int32_t x , int32_t y , BYTE npix )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
# ifdef DEBUGREC
C4RCSetPix rc ;
rc . x = x ; rc . y = y ; rc . clr = npix ;
AddDbgRec ( RCT_SetPix , & rc , sizeof ( rc ) ) ;
# endif
assert ( x > = 0 & & y > = 0 & & x < Width & & y < Height ) ;
2010-03-27 16:05:02 +00:00
// get and check pixel
BYTE opix = _GetPix ( x , y ) ;
2010-03-28 18:58:01 +00:00
if ( npix = = opix ) return true ;
2009-05-08 13:28:41 +00:00
// count pixels
2010-03-28 18:58:01 +00:00
if ( Pix2Dens [ npix ] )
{ if ( ! Pix2Dens [ opix ] ) PixCnt [ ( y / 15 ) + ( x / 17 ) * PixCntPitch ] + + ; }
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{ if ( Pix2Dens [ opix ] ) PixCnt [ ( y / 15 ) + ( x / 17 ) * PixCntPitch ] - - ; }
2010-03-27 16:05:02 +00:00
// count material
2009-05-08 13:28:41 +00:00
assert ( ! npix | | MatValid ( Pix2Mat [ npix ] ) ) ;
2010-03-27 16:05:02 +00:00
int32_t omat = Pix2Mat [ opix ] , nmat = Pix2Mat [ npix ] ;
2010-03-28 18:58:01 +00:00
if ( opix ) MatCount [ omat ] - - ;
if ( npix ) MatCount [ nmat ] + + ;
2010-03-27 16:05:02 +00:00
// count effective material
2010-03-28 18:58:01 +00:00
if ( omat ! = nmat )
{
if ( npix & & : : MaterialMap . Map [ nmat ] . MinHeightCount )
2010-03-27 16:05:02 +00:00
{
// Check for material above & below
int iMinHeight = : : MaterialMap . Map [ nmat ] . MinHeightCount ,
2010-03-28 18:58:01 +00:00
iBelow = GetMatHeight ( x , y + 1 , + 1 , nmat , iMinHeight ) ,
iAbove = GetMatHeight ( x , y - 1 , - 1 , nmat , iMinHeight ) ;
2010-03-27 16:05:02 +00:00
// Will be above treshold?
2010-03-28 18:58:01 +00:00
if ( iBelow + iAbove + 1 > = iMinHeight )
{
2010-03-27 16:05:02 +00:00
int iChange = 1 ;
// Check for heights below threshold
2010-03-28 18:58:01 +00:00
if ( iBelow < iMinHeight ) iChange + = iBelow ;
if ( iAbove < iMinHeight ) iChange + = iAbove ;
2010-03-27 16:05:02 +00:00
// Change
EffectiveMatCount [ nmat ] + = iChange ;
}
2010-03-28 18:58:01 +00:00
}
if ( opix & & : : MaterialMap . Map [ omat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
// Check for material above & below
int iMinHeight = : : MaterialMap . Map [ omat ] . MinHeightCount ,
2010-03-28 18:58:01 +00:00
iBelow = GetMatHeight ( x , y + 1 , + 1 , omat , iMinHeight ) ,
iAbove = GetMatHeight ( x , y - 1 , - 1 , omat , iMinHeight ) ;
2010-03-27 16:05:02 +00:00
// Not already below threshold?
2010-03-28 18:58:01 +00:00
if ( iBelow + iAbove + 1 > = iMinHeight )
{
2010-03-27 16:05:02 +00:00
int iChange = 1 ;
// Check for heights that will get below threshold
2010-03-28 18:58:01 +00:00
if ( iBelow < iMinHeight ) iChange + = iBelow ;
if ( iAbove < iMinHeight ) iChange + = iAbove ;
2010-03-27 16:05:02 +00:00
// Change
EffectiveMatCount [ omat ] - = iChange ;
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// set 8bpp-surface only!
Surface8 - > SetPix ( x , y , npix ) ;
// success
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
bool C4Landscape : : _SetPixIfMask ( int32_t x , int32_t y , BYTE npix , BYTE nMask )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// set 8bpp-surface only!
if ( _GetPix ( x , y ) = = nMask )
_SetPix ( x , y , npix ) ;
// success
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
bool C4Landscape : : CheckInstability ( int32_t tx , int32_t ty )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t mat = GetMat ( tx , ty ) ;
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . Instable )
return : : MassMover . Create ( tx , ty ) ;
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : CheckInstabilityRange ( int32_t tx , int32_t ty )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! CheckInstability ( tx , ty ) )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
CheckInstability ( tx , ty - 1 ) ;
CheckInstability ( tx , ty - 2 ) ;
CheckInstability ( tx - 1 , ty ) ;
CheckInstability ( tx + 1 , ty ) ;
}
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
void C4Landscape : : DrawMaterialRect ( int32_t mat , int32_t tx , int32_t ty , int32_t wdt , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t cx , cy ;
for ( cy = ty ; cy < ty + hgt ; cy + + )
for ( cx = tx ; cx < tx + wdt ; cx + + )
if ( ( MatDensity ( mat ) > GetDensity ( cx , cy ) )
| | ( ( MatDensity ( mat ) = = GetDensity ( cx , cy ) ) & & ( MatDigFree ( mat ) < = MatDigFree ( GetMat ( cx , cy ) ) ) ) )
SetPix ( cx , cy , Mat2PixColDefault ( mat ) + GBackIFT ( cx , cy ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : RaiseTerrain ( int32_t tx , int32_t ty , int32_t wdt )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t cx , cy ;
BYTE cpix ;
for ( cx = tx ; cx < tx + wdt ; cx + + )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
for ( cy = ty ; ( cy + 1 < GBackHgt ) & & ! GBackSolid ( cx , cy + 1 ) ; cy + + ) { }
if ( cy + 1 < GBackHgt ) if ( cy - ty < 20 )
{
cpix = GBackPix ( cx , cy + 1 ) ;
if ( ! MatVehicle ( PixCol2Mat ( cpix ) ) )
while ( cy > = ty ) { SetPix ( cx , cy , cpix ) ; cy - - ; }
}
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
int32_t C4Landscape : : ExtractMaterial ( int32_t fx , int32_t fy )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t mat = GetMat ( fx , fy ) ;
if ( mat = = MNone ) return MNone ;
FindMatTop ( mat , fx , fy ) ;
ClearPix ( fx , fy ) ;
CheckInstabilityRange ( fx , fy ) ;
return mat ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : InsertMaterial ( int32_t mat , int32_t tx , int32_t ty , int32_t vx , int32_t vy )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t mdens ;
if ( ! MatValid ( mat ) ) return false ;
mdens = MatDensity ( mat ) ;
if ( ! mdens ) return true ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Bounds
if ( ! Inside < int32_t > ( tx , 0 , Width - 1 ) | | ! Inside < int32_t > ( ty , 0 , Height ) ) return false ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
if ( Game . C4S . Game . Realism . LandscapePushPull )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
// Same or higher density?
if ( GetDensity ( tx , ty ) > = mdens )
// Push
if ( ! FindMatPathPush ( tx , ty , mdens , : : MaterialMap . Map [ mat ] . MaxSlide , ! ! : : MaterialMap . Map [ mat ] . Instable ) )
// Or die
return false ;
}
else
{
// Move up above same density
while ( mdens = = GetDensity ( tx , ty ) )
{
ty - - ; if ( ty < 0 ) return false ;
// Primitive slide (1)
if ( GetDensity ( tx - 1 , ty ) < mdens ) tx - - ;
if ( GetDensity ( tx + 1 , ty ) < mdens ) tx + + ;
}
// Stuck in higher density
if ( GetDensity ( tx , ty ) > mdens ) return false ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
// Try slide
while ( FindMatSlide ( tx , ty , + 1 , mdens , : : MaterialMap . Map [ mat ] . MaxSlide ) )
if ( GetDensity ( tx , ty + 1 ) < mdens )
{ : : PXS . Create ( mat , itofix ( tx ) , itofix ( ty ) , C4REAL10 ( vx ) , C4REAL10 ( vy ) ) ; return true ; }
2009-05-08 13:28:41 +00:00
2012-12-16 17:52:32 +00:00
// Try reaction with material below and at insertion position
2011-05-31 01:04:38 +00:00
C4MaterialReaction * pReact ; int32_t tmat ;
2012-12-16 17:52:32 +00:00
int32_t check_dir = 0 ;
for ( int32_t i = 0 ; i < 2 ; + + i )
2011-05-31 01:04:38 +00:00
{
2012-12-16 17:52:32 +00:00
if ( ( pReact = : : MaterialMap . GetReactionUnsafe ( mat , tmat = GetMat ( tx , ty + check_dir ) ) ) )
2011-05-31 01:04:38 +00:00
{
2012-12-16 17:52:32 +00:00
C4Real fvx = C4REAL10 ( vx ) , fvy = C4REAL10 ( vy ) ;
if ( ( * pReact - > pFunc ) ( pReact , tx , ty , tx , ty + check_dir , fvx , fvy , mat , tmat , meePXSPos , NULL ) )
{
// the material to be inserted killed itself in some material reaction below
return true ;
}
2011-05-31 01:04:38 +00:00
}
2012-12-16 17:52:32 +00:00
if ( ! ( check_dir = Sign ( GravAccel ) ) ) break ;
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-08-27 16:08:46 +00:00
// Insert as dead material
return InsertDeadMaterial ( mat , tx , ty ) ;
}
bool C4Landscape : : InsertDeadMaterial ( int32_t mat , int32_t tx , int32_t ty )
{
2011-10-01 17:32:16 +00:00
// Check bounds
if ( tx < 0 | | ty < 0 | | tx > = Width | | ty > = Height )
return false ;
2011-08-27 16:08:46 +00:00
// Save back original material so we can insert it later
2011-05-31 01:04:38 +00:00
int omat = 0 ;
if ( Game . C4S . Game . Realism . LandscapeInsertThrust )
omat = GetMat ( tx , ty ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Check surroundings for inspiration for texture to use
int n = 0 ; int pix = - 1 ;
if ( tx > 0 & & _GetMat ( tx - 1 , ty ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx - 1 , ty ) % IFT ;
if ( ty > 0 & & _GetMat ( tx , ty - 1 ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx , ty - 1 ) % IFT ;
if ( tx + 1 < Width & & _GetMat ( tx + 1 , ty ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx + 1 , ty ) % IFT ;
if ( ty + 1 < Height & & _GetMat ( tx , ty + 1 ) = = mat )
if ( ! Random ( + + n ) ) pix = _GetPix ( tx , ty + 1 ) % IFT ;
if ( pix < 0 )
pix = Mat2PixColDefault ( mat ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Insert dead material
SetPix ( tx , ty , pix + GBackIFT ( tx , ty ) ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Search a position for the old material pixel
if ( Game . C4S . Game . Realism . LandscapeInsertThrust & & MatValid ( omat ) )
InsertMaterial ( omat , tx , ty - 1 ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
return true ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : Incinerate ( int32_t x , int32_t y )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t mat = GetMat ( x , y ) ;
if ( MatValid ( mat ) )
if ( : : MaterialMap . Map [ mat ] . Inflammable )
// Not too much FLAMs
if ( ! Game . FindObject ( C4ID : : Flame , x - 4 , y - 1 , 8 , 20 ) )
if ( Game . CreateObject ( C4ID : : Flame , NULL , NO_OWNER , x , y ) )
return true ;
return false ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++ Polygon drawing code extracted from ALLEGRO by Shawn Hargreaves ++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2011-05-30 22:33:35 +00:00
struct CPolyEdge // An edge for the polygon drawer
{
int y ; // Current (starting at the top) y position
int bottom ; // bottom y position of this edge
int x ; // Fixed point x position
int dx ; // Fixed point x gradient
int w ; // Width of line segment
struct CPolyEdge * prev ; // Doubly linked list
struct CPolyEdge * next ;
} ;
# define POLYGON_FIX_SHIFT 16
static void fill_edge_structure ( CPolyEdge * edge , int * i1 , int * i2 )
{
if ( i2 [ 1 ] < i1 [ 1 ] ) // Swap
{ int * t = i1 ; i1 = i2 ; i2 = t ; }
edge - > y = i1 [ 1 ] ;
edge - > bottom = i2 [ 1 ] - 1 ;
edge - > dx = ( ( i2 [ 0 ] - i1 [ 0 ] ) < < POLYGON_FIX_SHIFT ) / ( i2 [ 1 ] - i1 [ 1 ] ) ;
edge - > x = ( i1 [ 0 ] < < POLYGON_FIX_SHIFT ) + ( 1 < < ( POLYGON_FIX_SHIFT - 1 ) ) - 1 ;
edge - > prev = NULL ;
edge - > next = NULL ;
if ( edge - > dx < 0 )
edge - > x + = Min < int > ( edge - > dx + ( 1 < < POLYGON_FIX_SHIFT ) , 0 ) ;
edge - > w = Max < int > ( Abs ( edge - > dx ) - ( 1 < < POLYGON_FIX_SHIFT ) , 0 ) ;
}
static CPolyEdge * add_edge ( CPolyEdge * list , CPolyEdge * edge , int sort_by_x )
{
CPolyEdge * pos = list ;
CPolyEdge * prev = NULL ;
if ( sort_by_x )
{
while ( ( pos ) & & ( pos - > x + pos - > w / 2 < edge - > x + edge - > w / 2 ) )
{ prev = pos ; pos = pos - > next ; }
}
else
{
while ( ( pos ) & & ( pos - > y < edge - > y ) )
{ prev = pos ; pos = pos - > next ; }
}
edge - > next = pos ;
edge - > prev = prev ;
if ( pos ) pos - > prev = edge ;
if ( prev ) { prev - > next = edge ; return list ; }
else return edge ;
}
static CPolyEdge * remove_edge ( CPolyEdge * list , CPolyEdge * edge )
{
if ( edge - > next ) edge - > next - > prev = edge - > prev ;
if ( edge - > prev ) { edge - > prev - > next = edge - > next ; return list ; }
else return edge - > next ;
}
// Global polygon quick buffer
const int QuickPolyBufSize = 20 ;
CPolyEdge QuickPolyBuf [ QuickPolyBufSize ] ;
2012-04-05 01:59:45 +00:00
int32_t C4Landscape : : ForPolygon ( int * vtcs , int length , bool ( C4Landscape : : * fnCallback ) ( int32_t , int32_t ) ,
2011-05-30 22:33:35 +00:00
C4MaterialList * mats_count , int col , uint8_t * conversion_table )
{
// Variables for polygon drawer
int c , x1 , x2 , y ;
int top = INT_MAX ;
int bottom = INT_MIN ;
int * i1 , * i2 ;
CPolyEdge * edge , * next_edge , * edgebuf ;
CPolyEdge * active_edges = NULL ;
CPolyEdge * inactive_edges = NULL ;
bool use_qpb = false ;
2012-04-05 01:59:45 +00:00
// Return value
int32_t amount = 0 ;
2011-05-30 22:33:35 +00:00
// Poly Buf
if ( length < = QuickPolyBufSize )
{ edgebuf = QuickPolyBuf ; use_qpb = true ; }
2012-04-05 01:59:45 +00:00
else if ( ! ( edgebuf = new CPolyEdge [ length ] ) ) { return 0 ; }
2011-05-30 22:33:35 +00:00
// Fill the edge table
edge = edgebuf ;
i1 = vtcs ;
i2 = vtcs + ( length - 1 ) * 2 ;
for ( c = 0 ; c < length ; c + + )
2010-03-28 18:58:01 +00:00
{
2011-05-30 22:33:35 +00:00
if ( i1 [ 1 ] ! = i2 [ 1 ] )
2010-03-28 18:58:01 +00:00
{
2011-05-30 22:33:35 +00:00
fill_edge_structure ( edge , i1 , i2 ) ;
if ( edge - > bottom > = edge - > y )
{
if ( edge - > y < top ) top = edge - > y ;
if ( edge - > bottom > bottom ) bottom = edge - > bottom ;
inactive_edges = add_edge ( inactive_edges , edge , false ) ;
edge + + ;
}
2010-03-28 18:58:01 +00:00
}
2011-05-30 22:33:35 +00:00
i2 = i1 ; i1 + = 2 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// For each scanline in the polygon...
for ( c = top ; c < = bottom ; c + + )
{
// Check for newly active edges
edge = inactive_edges ;
while ( ( edge ) & & ( edge - > y = = c ) )
{
next_edge = edge - > next ;
inactive_edges = remove_edge ( inactive_edges , edge ) ;
active_edges = add_edge ( active_edges , edge , true ) ;
edge = next_edge ;
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Draw horizontal line segments
edge = active_edges ;
while ( ( edge ) & & ( edge - > next ) )
{
x1 = edge - > x > > POLYGON_FIX_SHIFT ;
x2 = ( edge - > next - > x + edge - > next - > w ) > > POLYGON_FIX_SHIFT ;
y = c ;
// Fix coordinates
if ( x1 > x2 ) Swap ( x1 , x2 ) ;
// Set line
if ( conversion_table )
2012-01-30 19:54:17 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - ) Surface8 - > SetPix ( x1 + xcnt , y , conversion_table [ uint8_t ( GetPix ( x1 + xcnt , y ) ) ] ) ;
2011-05-30 22:33:35 +00:00
else if ( col )
2012-01-30 19:54:17 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - ) Surface8 - > SetPix ( x1 + xcnt , y , col ) ;
2011-05-30 22:33:35 +00:00
else
2012-01-30 19:54:17 +00:00
for ( int xcnt = x2 - x1 - 1 ; xcnt > = 0 ; xcnt - - )
2011-05-30 22:33:35 +00:00
{
int32_t mat = GetMat ( x1 + xcnt , y ) ;
if ( ( this - > * fnCallback ) ( x1 + xcnt , y ) )
if ( mats_count )
2012-04-05 01:59:45 +00:00
{
2011-05-30 22:33:35 +00:00
mats_count - > Add ( mat , 1 ) ;
2012-04-05 01:59:45 +00:00
amount + + ;
}
2011-05-30 22:33:35 +00:00
}
edge = edge - > next - > next ;
}
// Update edges, sorting and removing dead ones
edge = active_edges ;
while ( edge )
{
next_edge = edge - > next ;
if ( c > = edge - > bottom )
{
active_edges = remove_edge ( active_edges , edge ) ;
}
else
{
edge - > x + = edge - > dx ;
while ( ( edge - > prev ) & & ( edge - > x + edge - > w / 2 < edge - > prev - > x + edge - > prev - > w / 2 ) )
{
if ( edge - > next ) edge - > next - > prev = edge - > prev ;
edge - > prev - > next = edge - > next ;
edge - > next = edge - > prev ;
edge - > prev = edge - > prev - > prev ;
edge - > next - > prev = edge ;
if ( edge - > prev ) edge - > prev - > next = edge ;
else active_edges = edge ;
}
}
edge = next_edge ;
}
}
// Clear scratch memory
if ( ! use_qpb ) delete [ ] edgebuf ;
2012-04-05 01:59:45 +00:00
return amount ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++ Save, Init and load +++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ScenarioInit ( )
{
// Gravity
2012-07-25 15:02:10 +00:00
Gravity = C4REAL100 ( Game . C4S . Landscape . Gravity . Evaluate ( ) ) * DefaultGravAccel ;
2011-05-31 01:04:38 +00:00
// Opens
LeftOpen = Game . C4S . Landscape . LeftOpen ;
RightOpen = Game . C4S . Landscape . RightOpen ;
TopOpen = Game . C4S . Landscape . TopOpen ;
BottomOpen = Game . C4S . Landscape . BottomOpen ;
// Side open scan
if ( Game . C4S . Landscape . AutoScanSideOpen ) ScanSideOpen ( ) ;
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : Clear ( bool fClearMapCreator , bool fClearSky )
{
if ( pMapCreator & & fClearMapCreator ) { delete pMapCreator ; pMapCreator = NULL ; }
// clear sky
if ( fClearSky ) Sky . Clear ( ) ;
// clear surfaces, if assigned
delete pLandscapeRender ; pLandscapeRender = NULL ;
delete Surface8 ; Surface8 = NULL ;
delete Map ; Map = NULL ;
// clear initial landscape
delete [ ] pInitial ; pInitial = NULL ;
// clear scan
ScanX = 0 ;
Mode = C4LSC_Undefined ;
// clear pixel count
delete [ ] PixCnt ; PixCnt = NULL ;
PixCntPitch = 0 ;
// clear bridge material conversion temp buffers
for ( int32_t i = 0 ; i < C4MaxMaterial ; + + i )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
delete [ ] BridgeMatConversion [ i ] ;
BridgeMatConversion [ i ] = NULL ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
pComp - > Value ( mkNamingAdapt ( MapSeed , " MapSeed " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( LeftOpen , " LeftOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( RightOpen , " RightOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( TopOpen , " TopOpen " , 0 ) ) ;
pComp - > Value ( mkNamingAdapt ( BottomOpen , " BottomOpen " , 0 ) ) ;
2012-07-25 15:02:10 +00:00
pComp - > Value ( mkNamingAdapt ( mkCastIntAdapt ( Gravity ) , " Gravity " , DefaultGravAccel ) ) ;
2011-05-31 01:04:38 +00:00
pComp - > Value ( mkNamingAdapt ( Modulation , " MatModulation " , 0U ) ) ;
pComp - > Value ( mkNamingAdapt ( Mode , " Mode " , C4LSC_Undefined ) ) ;
}
2011-05-30 22:33:35 +00:00
2012-06-23 13:40:01 +00:00
static CSurface8 * GroupReadSurface8 ( C4Group & hGroup , const char * szWildCard )
2011-05-31 01:04:38 +00:00
{
2012-06-10 22:09:24 +00:00
if ( ! hGroup . AccessEntry ( szWildCard ) )
return NULL ;
2011-05-31 01:04:38 +00:00
// create surface
CSurface8 * pSfc = new CSurface8 ( ) ;
if ( ! pSfc - > Read ( hGroup ) )
{ delete pSfc ; return NULL ; }
return pSfc ;
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : Init ( C4Group & hGroup , bool fOverloadCurrent , bool fLoadSky , bool & rfLoaded , bool fSavegame )
{
// set map seed, if not pre-assigned
if ( ! MapSeed ) MapSeed = Random ( 3133700 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// increase max map size, since developers might set a greater one here
Game . C4S . Landscape . MapWdt . Max = 10000 ;
Game . C4S . Landscape . MapHgt . Max = 10000 ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// map and landscape must be initialized with fixed random, so runtime joining clients may recreate it
// with same seed
// after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating
// and not creating the map
// this, however, would cause syncloss to DebugRecs
C4DebugRecOff DBGRECOFF ( ! ! Game . C4S . Landscape . ExactLandscape ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
Game . FixRandom ( Game . RandomSeed ) ;
// map is like it's loaded for regular gamestart
// but it's changed and would have to be saved if a new section is loaded
fMapChanged = fOverloadCurrent ;
// don't change landscape mode in runtime joins
bool fLandscapeModeSet = ( Mode ! = C4LSC_Undefined ) ;
Game . SetInitProgress ( 60 ) ;
// create map if necessary
if ( ! Game . C4S . Landscape . ExactLandscape )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
CSurface8 * sfcMap = NULL ;
// Static map from scenario
2012-06-10 22:09:24 +00:00
if ( ( sfcMap = GroupReadSurface8 ( hGroup , C4CFN_Map ) ) )
if ( ! fLandscapeModeSet ) Mode = C4LSC_Static ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// dynamic map from file
if ( ! sfcMap )
if ( ( sfcMap = CreateMapS2 ( hGroup ) ) )
if ( ! fLandscapeModeSet ) Mode = C4LSC_Dynamic ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Dynamic map by scenario
if ( ! sfcMap & & ! fOverloadCurrent )
if ( ( sfcMap = CreateMap ( ) ) )
if ( ! fLandscapeModeSet ) Mode = C4LSC_Dynamic ;
2011-05-30 22:33:35 +00:00
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// No map failure
if ( ! sfcMap )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// no problem if only overloading
if ( ! fOverloadCurrent ) return false ;
if ( fLoadSky ) if ( ! Sky . Init ( fSavegame ) ) return false ;
2011-05-30 22:33:35 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
# ifdef DEBUGREC
AddDbgRec ( RCT_Block , " |---MAP---| " , 12 ) ;
AddDbgRec ( RCT_Map , sfcMap - > Bits , sfcMap - > Pitch * sfcMap - > Hgt ) ;
# endif
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Store map size and calculate map zoom
int iWdt , iHgt ;
sfcMap - > GetSurfaceSize ( iWdt , iHgt ) ;
MapWidth = iWdt ; MapHeight = iHgt ;
MapZoom = Game . C4S . Landscape . MapZoom . Evaluate ( ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Calculate landscape size
Width = MapZoom * MapWidth ;
Height = MapZoom * MapHeight ;
Width = Max < int32_t > ( Width , 100 ) ;
Height = Max < int32_t > ( Height , 100 ) ;
// Width = (Width/8)*8;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// if overloading, clear current landscape (and sections, etc.)
// must clear, of course, before new sky is eventually read
if ( fOverloadCurrent ) Clear ( ! Game . C4S . Landscape . KeepMapCreator , fLoadSky ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// assign new map
Map = sfcMap ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Sky (might need to know landscape height)
if ( fLoadSky )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
Game . SetInitProgress ( 70 ) ;
if ( ! Sky . Init ( fSavegame ) ) return false ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Exact landscape from scenario (no map or exact recreation)
else /* if (Game.C4S.Landscape.ExactLandscape) */
{
C4DebugRecOff DBGRECOFF ;
// if overloading, clear current
if ( fOverloadCurrent ) Clear ( ! Game . C4S . Landscape . KeepMapCreator , fLoadSky ) ;
// load it
if ( ! fLandscapeModeSet ) Mode = C4LSC_Exact ;
rfLoaded = true ;
if ( ! Load ( hGroup , fLoadSky , fSavegame ) ) return false ;
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Make pixel maps
UpdatePixMaps ( ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// progress
Game . SetInitProgress ( 80 ) ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// copy noscan-var
NoScan = Game . C4S . Landscape . NoScan ! = 0 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Scan settings
ScanSpeed = BoundBy ( Width / 500 , 2 , 15 ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// map to big surface and sectionize it
// (not for shaders though - they require continous textures)
2012-06-10 22:09:24 +00:00
if ( ! Game . C4S . Landscape . ExactLandscape )
2010-03-28 18:58:01 +00:00
{
2012-06-10 22:09:24 +00:00
// Create landscape surface
Surface8 = new CSurface8 ( ) ;
if ( ! Surface8 - > Create ( Width , Height ) | | ! Mat2Pal ( ) )
{
delete Surface8 ; Surface8 = 0 ;
return false ;
}
2009-05-08 13:28:41 +00:00
2012-06-10 22:09:24 +00:00
// Map to landscape
if ( ! MapToLandscape ( ) ) return false ;
}
2011-05-31 01:04:38 +00:00
Game . SetInitProgress ( 84 ) ;
2009-05-08 13:28:41 +00:00
2011-07-17 14:52:36 +00:00
# ifdef DEBUGREC
AddDbgRec ( RCT_Block , " |---LANDSCAPE---| " , 18 ) ;
AddDbgRec ( RCT_Map , Surface8 - > Bits , Surface8 - > Pitch * Surface8 - > Hgt ) ;
# endif
2011-05-31 01:04:38 +00:00
// Create renderer
pLandscapeRender = NULL ;
# ifdef USE_GL
if ( ! pLandscapeRender & & : : Config . Graphics . HighResLandscape )
pLandscapeRender = new C4LandscapeRenderGL ( ) ;
# endif
# ifndef USE_CONSOLE
if ( ! pLandscapeRender )
pLandscapeRender = new C4LandscapeRenderClassic ( ) ;
# endif
if ( pLandscapeRender )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Initialize renderer
if ( ! pLandscapeRender - > Init ( Width , Height , & : : TextureMap , & : : GraphicsResource . Files ) )
return false ;
// Write landscape data
pLandscapeRender - > Update ( C4Rect ( 0 , 0 , Width , Height ) , this ) ;
Game . SetInitProgress ( 87 ) ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
# ifdef DEBUGREC
AddDbgRec ( RCT_Block , " |---LS---| " , 11 ) ;
AddDbgRec ( RCT_Ls , Surface8 - > Bits , Surface8 - > Pitch * Surface8 - > Hgt ) ;
# endif
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Create pixel count array
// We will use 15x17 blocks so the pixel count can't get over 255.
int32_t PixCntWidth = ( Width + 16 ) / 17 ;
PixCntPitch = ( Height + 14 ) / 15 ;
PixCnt = new uint8_t [ PixCntWidth * PixCntPitch ] ;
UpdatePixCnt ( C4Rect ( 0 , 0 , Width , Height ) ) ;
ClearMatCount ( ) ;
UpdateMatCnt ( C4Rect ( 0 , 0 , Width , Height ) , true ) ;
2011-05-27 00:51:07 +00:00
2011-05-31 01:04:38 +00:00
// Save initial landscape
if ( ! SaveInitial ( ) )
return false ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Load diff, if existant
ApplyDiff ( hGroup ) ;
// after map/landscape creation, the seed must be fixed again, so there's no difference between clients creating
// and not creating the map
Game . FixRandom ( Game . RandomSeed ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Success
rfLoaded = true ;
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
2011-05-31 01:04:38 +00:00
bool C4Landscape : : Save ( C4Group & hGroup )
{
C4SolidMask : : RemoveSolidMasks ( ) ;
bool r = SaveInternal ( hGroup ) ;
C4SolidMask : : PutSolidMasks ( ) ;
return r ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : DebugSave ( const char * szFilename )
{
// debug: Save 8 bit data landscape only, without doing any SolidMask-removal-stuff
bool fSuccess = false ;
if ( Surface8 )
{
fSuccess = Surface8 - > Save ( szFilename ) ;
}
return fSuccess ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : SaveInternal ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Save landscape surface
char szTempLandscape [ _MAX_PATH + 1 ] ;
SCopy ( Config . AtTempPath ( C4CFN_TempLandscape ) , szTempLandscape ) ;
MakeTempFilename ( szTempLandscape ) ;
if ( ! Surface8 - > Save ( szTempLandscape ) )
return false ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Move temp file to group
if ( ! hGroup . Move ( szTempLandscape , C4CFN_Landscape ) )
return false ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Save map
if ( fMapChanged & & Map )
if ( ! SaveMap ( hGroup ) )
return false ;
// save textures (if changed)
if ( ! SaveTextures ( hGroup ) )
return false ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : SaveDiff ( C4Group & hGroup , bool fSyncSave )
{
C4SolidMask : : RemoveSolidMasks ( ) ;
bool r = SaveDiffInternal ( hGroup , fSyncSave ) ;
C4SolidMask : : PutSolidMasks ( ) ;
return r ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : SaveDiffInternal ( C4Group & hGroup , bool fSyncSave )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
assert ( pInitial ) ;
if ( ! pInitial ) return false ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// If it shouldn't be sync-save: Clear all bytes that have not changed
bool fChanged = false ;
if ( ! fSyncSave )
for ( int y = 0 ; y < Height ; y + + )
for ( int x = 0 ; x < Width ; x + + )
if ( pInitial [ y * Width + x ] = = _GetPix ( x , y ) )
Surface8 - > SetPix ( x , y , 0xff ) ;
else
fChanged = true ;
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
if ( fSyncSave | | fChanged )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Save landscape surface
if ( ! Surface8 - > Save ( Config . AtTempPath ( C4CFN_TempLandscape ) ) )
return false ;
// Move temp file to group
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempLandscape ) ,
C4CFN_DiffLandscape ) )
return false ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
2011-05-31 01:04:38 +00:00
// Restore landscape pixels
if ( ! fSyncSave )
if ( pInitial )
for ( int y = 0 ; y < Height ; y + + )
for ( int x = 0 ; x < Width ; x + + )
if ( _GetPix ( x , y ) = = 0xff )
Surface8 - > SetPix ( x , y , pInitial [ y * Width + x ] ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Save changed map, too
if ( fMapChanged & & Map )
if ( ! SaveMap ( hGroup ) ) return false ;
// and textures (if changed)
if ( ! SaveTextures ( hGroup ) ) return false ;
return true ;
}
bool C4Landscape : : SaveInitial ( )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Create array
delete [ ] pInitial ;
pInitial = new BYTE [ Width * Height ] ;
// Save material data
for ( int y = 0 ; y < Height ; y + + )
for ( int x = 0 ; x < Width ; x + + )
pInitial [ y * Width + x ] = _GetPix ( x , y ) ;
return true ;
}
bool C4Landscape : : Load ( C4Group & hGroup , bool fLoadSky , bool fSavegame )
{
// Load exact landscape from group
2012-06-10 22:09:24 +00:00
if ( ! ( Surface8 = GroupReadSurface8 ( hGroup , C4CFN_Landscape ) ) ) return false ;
2011-05-31 01:04:38 +00:00
int iWidth , iHeight ;
Surface8 - > GetSurfaceSize ( iWidth , iHeight ) ;
Width = iWidth ; Height = iHeight ;
// adjust pal
if ( ! Mat2Pal ( ) ) return false ;
2012-06-10 22:09:24 +00:00
// Landscape should be in correct format: Make sure it is!
for ( int32_t y = 0 ; y < Height ; + + y )
for ( int32_t x = 0 ; x < Width ; + + x )
{
BYTE byPix = Surface8 - > GetPix ( x , y ) ;
int32_t iMat = PixCol2Mat ( byPix ) ;
if ( byPix & & ! MatValid ( iMat ) )
2010-03-28 18:58:01 +00:00
{
2012-06-10 22:09:24 +00:00
LogFatal ( FormatString ( " Landscape loading error at (%d/%d): Pixel value %d not a valid material! " , ( int ) x , ( int ) y , ( int ) byPix ) . getData ( ) ) ;
return false ;
2009-05-08 13:28:41 +00:00
}
2012-06-10 22:09:24 +00:00
}
2011-05-31 01:04:38 +00:00
// Init sky
if ( fLoadSky )
{
Game . SetInitProgress ( 70 ) ;
if ( ! Sky . Init ( fSavegame ) ) return false ;
}
// Success
2009-08-15 18:50:32 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : ApplyDiff ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
CSurface8 * pDiff ;
// Load diff landscape from group
2012-06-10 22:09:24 +00:00
if ( ! ( pDiff = GroupReadSurface8 ( hGroup , C4CFN_DiffLandscape ) ) ) return false ;
2011-05-31 01:04:38 +00:00
// convert all pixels: keep if same material; re-set if different material
BYTE byPix ;
for ( int32_t y = 0 ; y < Height ; + + y ) for ( int32_t x = 0 ; x < Width ; + + x )
if ( pDiff - > GetPix ( x , y ) ! = 0xff )
if ( Surface8 - > GetPix ( x , y ) ! = ( byPix = pDiff - > GetPix ( x , y ) ) )
// material has changed here: readjust with new texture
SetPix ( x , y , byPix ) ;
// done; clear diff
delete pDiff ;
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
2011-05-31 01:04:38 +00:00
void C4Landscape : : Default ( )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
Mode = C4LSC_Undefined ;
Surface8 = NULL ;
pLandscapeRender = NULL ;
Map = NULL ;
Width = Height = 0 ;
MapWidth = MapHeight = MapZoom = 0 ;
ClearMatCount ( ) ;
ScanX = 0 ;
ScanSpeed = 2 ;
LeftOpen = RightOpen = TopOpen = BottomOpen = 0 ;
2012-07-25 15:02:10 +00:00
Gravity = DefaultGravAccel ;
2011-05-31 01:04:38 +00:00
MapSeed = 0 ; NoScan = false ;
pMapCreator = NULL ;
Modulation = 0 ;
fMapChanged = false ;
for ( int32_t i = 0 ; i < C4MaxMaterial ; + + i )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
delete [ ] BridgeMatConversion [ i ] ;
BridgeMatConversion [ i ] = NULL ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : ClearMatCount ( )
{
for ( int32_t cnt = 0 ; cnt < C4MaxMaterial ; cnt + + )
2011-05-30 22:33:35 +00:00
{
2011-05-31 01:04:38 +00:00
MatCount [ cnt ] = 0 ;
EffectiveMatCount [ cnt ] = 0 ;
2011-05-30 22:33:35 +00:00
}
2011-05-31 01:04:38 +00:00
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : Synchronize ( )
{
ScanX = 0 ;
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
int32_t PixCol2Mat ( BYTE pixc )
{
// Get texture
int32_t iTex = PixCol2Tex ( pixc ) ;
if ( ! iTex ) return MNone ;
// Get material-texture mapping
const C4TexMapEntry * pTex = : : TextureMap . GetEntry ( iTex ) ;
// Return material
return pTex ? pTex - > GetMaterialIndex ( ) : MNone ;
}
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : SaveMap ( C4Group & hGroup )
{
// No map
if ( ! Map ) return false ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Create map palette
2012-08-15 22:45:27 +00:00
CStdPalette Palette ;
: : TextureMap . StoreMapPalette ( & Palette , : : MaterialMap ) ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Save map surface
2012-08-15 22:45:27 +00:00
if ( ! Map - > Save ( Config . AtTempPath ( C4CFN_TempMap ) , & Palette ) )
2011-05-31 01:04:38 +00:00
return false ;
2011-05-30 22:33:35 +00:00
2011-05-31 01:04:38 +00:00
// Move temp file to group
if ( ! hGroup . Move ( Config . AtTempPath ( C4CFN_TempMap ) ,
C4CFN_Map ) )
return false ;
2011-05-30 22:33:35 +00:00
// Success
return true ;
}
2011-05-31 01:04:38 +00:00
bool C4Landscape : : SaveTextures ( C4Group & hGroup )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// if material-texture-combinations have been added, write the texture map
if ( : : TextureMap . fEntriesAdded )
{
C4Group * pMatGroup = new C4Group ( ) ;
bool fSuccess = false ;
// create local material group
if ( ! hGroup . FindEntry ( C4CFN_Material ) )
{
// delete previous item at temp path
EraseItem ( Config . AtTempPath ( C4CFN_Material ) ) ;
// create at temp path
if ( pMatGroup - > Open ( Config . AtTempPath ( C4CFN_Material ) , true ) )
// write to it
if ( : : TextureMap . SaveMap ( * pMatGroup , C4CFN_TexMap ) )
// close (flush)
if ( pMatGroup - > Close ( ) )
// add it
if ( hGroup . Move ( Config . AtTempPath ( C4CFN_Material ) , C4CFN_Material ) )
fSuccess = true ;
// temp group must remain for scenario file closure
// it will be deleted when the group is closed
}
else
// simply write it to the local material file
if ( pMatGroup - > OpenAsChild ( & hGroup , C4CFN_Material ) )
fSuccess = : : TextureMap . SaveMap ( * pMatGroup , C4CFN_TexMap ) ;
// close material group again
if ( pMatGroup - > IsOpen ( ) ) pMatGroup - > Close ( ) ;
delete pMatGroup ;
// fail if unsuccessful
if ( ! fSuccess ) return false ;
}
// done, success
return true ;
2010-04-20 20:38:18 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : MapToLandscape ( )
2010-04-20 20:38:18 +00:00
{
2011-05-31 01:04:38 +00:00
// zoom map to landscape
return MapToLandscape ( Map , 0 , 0 , MapWidth , MapHeight ) ;
}
2009-05-08 13:28:41 +00:00
2011-09-02 23:22:12 +00:00
uint32_t C4Landscape : : ChunkyRandom ( uint32_t & iOffset , uint32_t iRange )
2011-05-31 01:04:38 +00:00
{
if ( ! iRange ) return 0 ;
2011-09-02 23:22:12 +00:00
iOffset = ( iOffset * 16807 ) % 2147483647 ;
return ( iOffset ^ MapSeed ) % iRange ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-09-07 12:25:32 +00:00
void C4Landscape : : DrawChunk ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , int32_t mcol , C4MaterialCoreShape Shape , uint32_t cro )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
unsigned int top_rough = 0 , side_rough = 0 , bottom_rough = 0 ;
2011-05-31 01:04:38 +00:00
// what to do?
2011-09-07 12:25:32 +00:00
switch ( Shape )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
case C4M_Flat : case C4M_Octagon :
2011-09-02 23:22:12 +00:00
Surface8 - > Box ( tx , ty , tx + wdt , ty + hgt , mcol ) ;
2011-05-31 01:04:38 +00:00
return ;
case C4M_TopFlat :
2011-09-07 12:25:32 +00:00
top_rough = 0 ; side_rough = 2 ; bottom_rough = 4 ;
2011-05-31 01:04:38 +00:00
break ;
case C4M_Smooth :
2011-09-07 12:25:32 +00:00
top_rough = 2 ; side_rough = 2 ; bottom_rough = 2 ;
2011-05-31 01:04:38 +00:00
break ;
case C4M_Rough :
2011-09-07 12:25:32 +00:00
top_rough = 4 ; side_rough = 4 ; bottom_rough = 4 ;
break ;
case C4M_Smoother :
top_rough = 1 ; side_rough = 1 ; bottom_rough = 1 ;
2011-05-31 01:04:38 +00:00
break ;
}
int vtcs [ 16 ] ;
2011-09-07 12:25:32 +00:00
unsigned int rx = Max ( wdt / 2 , 1 ) ;
2009-05-08 13:28:41 +00:00
2011-09-07 12:25:32 +00:00
vtcs [ 0 ] = tx - ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 1 ] = ty - ChunkyRandom ( cro , rx * top_rough / 4 ) ;
vtcs [ 2 ] = tx - ChunkyRandom ( cro , rx * side_rough / 2 ) ; vtcs [ 3 ] = ty + hgt / 2 ;
vtcs [ 4 ] = tx - ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 5 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 4 ) ;
vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 2 ) ;
vtcs [ 8 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 9 ] = ty + hgt + ChunkyRandom ( cro , rx * bottom_rough / 4 ) ;
vtcs [ 10 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 2 ) ; vtcs [ 11 ] = ty + hgt / 2 ;
vtcs [ 12 ] = tx + wdt + ChunkyRandom ( cro , rx * side_rough / 4 ) ; vtcs [ 13 ] = ty - ChunkyRandom ( cro , rx * top_rough / 4 ) ;
vtcs [ 14 ] = tx + wdt / 2 ; vtcs [ 15 ] = ty - ChunkyRandom ( cro , rx * top_rough / 2 ) ;
2009-05-08 13:28:41 +00:00
2011-09-02 23:22:12 +00:00
ForPolygon ( vtcs , 8 , NULL , NULL , mcol ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-09-07 12:25:32 +00:00
void C4Landscape : : DrawSmoothOChunk ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , int32_t mcol , int flip , uint32_t cro )
2010-04-20 20:38:18 +00:00
{
2011-05-31 01:04:38 +00:00
int vtcs [ 8 ] ;
2011-09-07 12:25:32 +00:00
unsigned int rx = Max ( wdt / 2 , 1 ) ;
2010-04-20 20:38:18 +00:00
2011-09-07 12:25:32 +00:00
vtcs [ 0 ] = tx ; vtcs [ 1 ] = ty ;
2011-09-02 23:22:12 +00:00
vtcs [ 2 ] = tx ; vtcs [ 3 ] = ty + hgt ;
vtcs [ 4 ] = tx + wdt ; vtcs [ 5 ] = ty + hgt ;
2011-09-07 12:25:32 +00:00
vtcs [ 6 ] = tx + wdt ; vtcs [ 7 ] = ty ;
2009-05-08 13:28:41 +00:00
2011-09-07 12:25:32 +00:00
switch ( flip )
{
case 0 : vtcs [ 0 ] = tx + wdt / 2 ; vtcs [ 1 ] + = hgt / 3 ; vtcs [ 7 ] - = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 1 : vtcs [ 2 ] = tx + wdt / 2 ; vtcs [ 3 ] - = hgt / 3 ; vtcs [ 5 ] + = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 2 : vtcs [ 4 ] = tx + wdt / 2 ; vtcs [ 5 ] - = hgt / 3 ; vtcs [ 3 ] + = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 3 : vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] + = hgt / 3 ; vtcs [ 1 ] - = ChunkyRandom ( cro , rx / 2 ) ; break ;
case 4 : vtcs [ 0 ] = tx + wdt / 2 ; vtcs [ 1 ] + = hgt / 2 ; break ;
case 5 : vtcs [ 2 ] = tx + wdt / 2 ; vtcs [ 3 ] - = hgt / 2 ; break ;
case 6 : vtcs [ 4 ] = tx + wdt / 2 ; vtcs [ 5 ] - = hgt / 2 ; break ;
case 7 : vtcs [ 6 ] = tx + wdt / 2 ; vtcs [ 7 ] + = hgt / 2 ; break ;
}
2009-05-08 13:28:41 +00:00
2011-09-02 23:22:12 +00:00
ForPolygon ( vtcs , 4 , NULL , NULL , mcol ) ;
2011-05-31 01:04:38 +00:00
}
2010-03-28 18:58:01 +00:00
2011-07-16 19:50:49 +00:00
void C4Landscape : : DrawCustomShapePoly ( const C4MaterialShape : : Poly & poly , int32_t off_x , int32_t off_y , int32_t mcol )
{
// put poly into plain int array format; add offset and send to polygon drawing proc
size_t n = poly . size ( ) , i = 0 ;
int * vtcs = new int [ n * 2 ] ;
for ( C4MaterialShape : : Poly : : const_iterator j = poly . begin ( ) ; j ! = poly . end ( ) ; + + j )
{
vtcs [ i + + ] = j - > x + off_x ;
vtcs [ i + + ] = j - > y + off_y ;
}
ForPolygon ( vtcs , n , NULL , NULL , mcol ) ;
// done
delete [ ] vtcs ;
}
void C4Landscape : : DrawCustomShape ( CSurface8 * sfcMap , C4MaterialShape * shape , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iTexture , int32_t mcol , int32_t iOffX , int32_t iOffY )
{
// Prepare shape for map zoom
if ( ! shape - > PrepareForZoom ( MapZoom ) )
{
DebugLogF ( " ERROR: Cannot apply texture index %d: Material shape size not a multiple of map zoom! " , ( int ) mcol ) ;
return ;
}
// Get affected range of shapes
// range in pixels
int32_t x0 = iMapX * MapZoom , y0 = iMapY * MapZoom ;
int32_t x1 = x0 + iMapWdt * MapZoom , y1 = y0 + iMapHgt * MapZoom ;
// range in shape blocks
x0 = ( x0 - shape - > overlap_right + shape - > wdt ) / shape - > wdt - 1 ;
y0 = ( y0 - shape - > overlap_bottom + shape - > hgt ) / shape - > hgt - 1 ;
x1 = ( x1 + shape - > overlap_left + shape - > wdt ) / shape - > wdt - 1 ;
y1 = ( y1 + shape - > overlap_top + shape - > hgt ) / shape - > hgt - 1 ;
BYTE iIFT = 0 ;
// paint from all affected shape blocks
for ( int32_t y = y0 ; y < = y1 ; + + y )
for ( int32_t x = x0 ; x < = x1 ; + + x )
{
int32_t x_map = x * shape - > wdt / MapZoom , y_map = y * shape - > hgt / MapZoom ;
for ( C4MaterialShape : : PolyVec : : const_iterator i = shape - > polys . begin ( ) ; i ! = shape - > polys . end ( ) ; + + i )
{
const C4MaterialShape : : Poly & p = * i ;
// does this shape block overlap any map pixels of our material
for ( C4MaterialShape : : PtVec : : const_iterator j = p . overlaps . begin ( ) ; j ! = p . overlaps . end ( ) ; + + j )
{
BYTE pix ;
if ( ( ( pix = sfcMap - > GetPix ( x_map + j - > x , y_map + j - > y ) ) & 127 ) = = iTexture )
{
// first pixel in overlap list determines IFT
iIFT = pix & IFT ;
// draw this poly!
DrawCustomShapePoly ( p , x_map * MapZoom + iOffX , y_map * MapZoom + iOffY , iIFT + mcol ) ;
break ;
}
}
}
}
}
2011-05-31 01:04:38 +00:00
void C4Landscape : : ChunkOZoom ( CSurface8 * sfcMap , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iTexture , int32_t iOffX , int32_t iOffY )
{
C4Material * pMaterial = : : TextureMap . GetEntry ( iTexture ) - > GetMaterial ( ) ;
if ( ! pMaterial ) return ;
2011-09-07 12:25:32 +00:00
C4MaterialCoreShape iChunkType = pMaterial - > MapChunkType ;
BYTE byColor = MatTex2PixCol ( iTexture ) ;
2011-05-31 01:04:38 +00:00
// Get map & landscape size
2011-09-07 12:25:32 +00:00
int iMapWidth , iMapHeight ;
sfcMap - > GetSurfaceSize ( iMapWidth , iMapHeight ) ;
2011-05-31 01:04:38 +00:00
// Clip desired map segment to map size
2011-09-07 12:25:32 +00:00
iMapX = BoundBy < int32_t > ( iMapX , 0 , iMapWidth - 1 ) ;
iMapY = BoundBy < int32_t > ( iMapY , 0 , iMapHeight - 1 ) ;
iMapWdt = BoundBy < int32_t > ( iMapWdt , 0 , iMapWidth - iMapX ) ;
iMapHgt = BoundBy < int32_t > ( iMapHgt , 0 , iMapHeight - iMapY ) ;
2011-05-31 01:04:38 +00:00
// get chunk size
2011-09-07 12:25:32 +00:00
int iChunkWidth = MapZoom , iChunkHeight = MapZoom ;
2011-05-31 01:04:38 +00:00
// Scan map lines
2011-09-07 12:25:32 +00:00
for ( int iY = iMapY ; iY < iMapY + iMapHgt ; iY + + )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Landscape target coordinate vertical
int iToY = iY * iChunkHeight + iOffY ;
// Scan map line
for ( int iX = iMapX ; iX < iMapX + iMapWdt ; iX + + )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
int32_t iIFT ;
// Map scan line start
uint8_t MapPixel = sfcMap - > _GetPix ( iX , iY ) ;
// Landscape target coordinate horizontal
int iToX = iX * iChunkWidth + iOffX ;
// Here's a chunk of the texture-material to zoom
if ( ( MapPixel & 127 ) = = iTexture )
{
// Determine IFT
iIFT = 0 ; if ( MapPixel > = 128 ) iIFT = IFT ;
// Draw chunk
DrawChunk ( iToX , iToY , iChunkWidth , iChunkHeight , byColor + iIFT , iChunkType , ( iX < < 16 ) + iY ) ;
}
// Other chunk, check for slope smoothers
else if ( iChunkType = = C4M_Smooth | | iChunkType = = C4M_Smoother | | iChunkType = = C4M_Octagon )
2011-05-31 01:04:38 +00:00
{
2011-07-16 19:50:49 +00:00
// Map scan line pixel below
2011-09-07 12:25:32 +00:00
uint8_t below = sfcMap - > GetPix ( iX , iY + 1 ) & 127 ;
uint8_t above = sfcMap - > GetPix ( iX , iY - 1 ) & 127 ;
uint8_t left = sfcMap - > GetPix ( iX - 1 , iY ) & 127 ;
uint8_t right = sfcMap - > GetPix ( iX + 1 , iY ) & 127 ;
// do not fill a tiny hole
if ( below = = iTexture & & above = = iTexture & & left = = iTexture & & right = = iTexture )
continue ;
int flat = iChunkType = = C4M_Octagon ? 4 : 0 ;
// Smooth chunk & same texture-material below
if ( iY < iMapHeight - 1 & & below = = iTexture )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Same texture-material on left
if ( iX > 0 & & left = = iTexture )
{
// Determine IFT
iIFT = 0 ; if ( sfcMap - > GetPix ( iX - 1 , iY ) > = 128 ) iIFT = IFT ;
// Draw smoother
DrawSmoothOChunk ( iToX , iToY , iChunkWidth , iChunkHeight , byColor + iIFT , 3 + flat , ( iX < < 16 ) + iY ) ;
}
// Same texture-material on right
if ( iX < iMapWidth - 1 & & right = = iTexture )
{
// Determine IFT
iIFT = 0 ; if ( sfcMap - > GetPix ( iX + 1 , iY ) > = 128 ) iIFT = IFT ;
// Draw smoother
DrawSmoothOChunk ( iToX , iToY , iChunkWidth , iChunkHeight , byColor + iIFT , 0 + flat , ( iX < < 16 ) + iY ) ;
}
2011-07-16 19:50:49 +00:00
}
2011-09-07 12:25:32 +00:00
// Smooth chunk & same texture-material above
if ( iY > 0 & & above = = iTexture )
{
// Same texture-material on left
if ( iX > 0 & & left = = iTexture )
{
// Determine IFT
iIFT = 0 ; if ( sfcMap - > GetPix ( iX - 1 , iY ) > = 128 ) iIFT = IFT ;
// Draw smoother
DrawSmoothOChunk ( iToX , iToY , iChunkWidth , iChunkHeight , byColor + iIFT , 2 + flat , ( iX < < 16 ) + iY ) ;
}
// Same texture-material on right
if ( iX < iMapWidth - 1 & & right = = iTexture )
2011-05-31 01:04:38 +00:00
{
2011-09-07 12:25:32 +00:00
// Determine IFT
iIFT = 0 ; if ( sfcMap - > GetPix ( iX + 1 , iY ) > = 128 ) iIFT = IFT ;
// Draw smoother
DrawSmoothOChunk ( iToX , iToY , iChunkWidth , iChunkHeight , byColor + iIFT , 1 + flat , ( iX < < 16 ) + iY ) ;
2011-05-31 01:04:38 +00:00
}
2011-09-07 12:25:32 +00:00
}
2011-07-16 19:50:49 +00:00
}
2011-05-31 01:04:38 +00:00
}
2010-03-28 18:58:01 +00:00
}
2011-07-16 19:50:49 +00:00
// Draw custom shapes on top of regular materials
if ( pMaterial - > CustomShape ) DrawCustomShape ( sfcMap , pMaterial - > CustomShape , iMapX , iMapY , iMapWdt , iMapHgt , iTexture , byColor , iOffX , iOffY ) ;
2011-05-31 01:04:38 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : GetTexUsage ( CSurface8 * sfcMap , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , DWORD * dwpTextureUsage )
{
int iX , iY ;
// No good parameters
if ( ! sfcMap | | ! dwpTextureUsage ) return false ;
// Clip desired map segment to map size
iMapX = BoundBy < int32_t > ( iMapX , 0 , sfcMap - > Wdt - 1 ) ; iMapY = BoundBy < int32_t > ( iMapY , 0 , sfcMap - > Hgt - 1 ) ;
iMapWdt = BoundBy < int32_t > ( iMapWdt , 0 , sfcMap - > Wdt - iMapX ) ; iMapHgt = BoundBy < int32_t > ( iMapHgt , 0 , sfcMap - > Hgt - iMapY ) ;
// Zero texture usage list
for ( int32_t cnt = 0 ; cnt < C4M_MaxTexIndex ; cnt + + ) dwpTextureUsage [ cnt ] = 0 ;
// Scan map pixels
for ( iY = iMapY ; iY < iMapY + iMapHgt ; iY + + )
for ( iX = iMapX ; iX < iMapX + iMapWdt ; iX + + )
// Count texture map index only (no IFT)
dwpTextureUsage [ sfcMap - > GetPix ( iX , iY ) & ( IFT - 1 ) ] + + ;
// Done
return true ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : TexOZoom ( CSurface8 * sfcMap , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , DWORD * dwpTextureUsage , int32_t iToX , int32_t iToY )
{
int32_t iIndex ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// ChunkOZoom all used textures
for ( iIndex = 1 ; iIndex < C4M_MaxTexIndex ; iIndex + + )
if ( dwpTextureUsage [ iIndex ] > 0 )
{
// ChunkOZoom map to landscape
ChunkOZoom ( sfcMap , iMapX , iMapY , iMapWdt , iMapHgt , iIndex , iToX , iToY ) ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +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
2012-02-11 22:24:53 +00:00
bool C4Landscape : : MapToSurface ( CSurface8 * sfcMap , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iToX , int32_t iToY , int32_t iToWdt , int32_t iToHgt , int32_t iOffX , int32_t iOffY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// assign clipper
Surface8 - > Clip ( iToX , iToY , iToX + iToWdt - 1 , iToY + iToHgt - 1 ) ;
2011-10-03 14:30:18 +00:00
pDraw - > NoPrimaryClipper ( ) ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Enlarge map segment for chunky rim
2011-07-16 19:50:49 +00:00
iMapX - = 2 + MaterialMap . max_shape_width / MapZoom ;
iMapY - = 2 + MaterialMap . max_shape_height / MapZoom ;
iMapWdt + = 4 + MaterialMap . max_shape_width / MapZoom * 2 ;
iMapHgt + = 4 + MaterialMap . max_shape_height / MapZoom * 2 ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Determine texture usage in map segment
DWORD dwTexUsage [ C4M_MaxTexIndex ] ;
if ( ! GetTexUsage ( sfcMap , iMapX , iMapY , iMapWdt , iMapHgt , dwTexUsage ) ) return false ;
// Texture zoom map to landscape
if ( ! TexOZoom ( sfcMap , iMapX , iMapY , iMapWdt , iMapHgt , dwTexUsage , iOffX , iOffY ) ) return false ;
// remove clipper
Surface8 - > NoClip ( ) ;
// success
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
2012-02-10 20:48:48 +00:00
bool C4Landscape : : MapToLandscape ( CSurface8 * sfcMap , int32_t iMapX , int32_t iMapY , int32_t iMapWdt , int32_t iMapHgt , int32_t iOffsX , int32_t iOffsY , bool noClear )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
assert ( Surface8 ) ;
// Clip to map/landscape segment
int iMapWidth , iMapHeight , iLandscapeWidth , iLandscapeHeight ;
// Get map & landscape size
sfcMap - > GetSurfaceSize ( iMapWidth , iMapHeight ) ;
Surface8 - > GetSurfaceSize ( iLandscapeWidth , iLandscapeHeight ) ;
// Clip map segment to map size
iMapX = BoundBy < int32_t > ( iMapX , 0 , iMapWidth - 1 ) ; iMapY = BoundBy < int32_t > ( iMapY , 0 , iMapHeight - 1 ) ;
iMapWdt = BoundBy < int32_t > ( iMapWdt , 0 , iMapWidth - iMapX ) ; iMapHgt = BoundBy < int32_t > ( iMapHgt , 0 , iMapHeight - iMapY ) ;
// No segment
if ( ! iMapWdt | | ! iMapHgt ) return true ;
// Get affected landscape rect
C4Rect To ;
To . x = iMapX * MapZoom + iOffsX ;
To . y = iMapY * MapZoom + iOffsY ;
To . Wdt = iMapWdt * MapZoom ;
To . Hgt = iMapHgt * MapZoom ;
PrepareChange ( To ) ;
2012-02-11 22:24:53 +00:00
// clear the old landscape if not surpressed
if ( ! noClear )
Surface8 - > ClearBox8Only ( To . x , To . y , To . Wdt , To . Hgt ) ;
MapToSurface ( sfcMap , iMapX , iMapY , iMapWdt , iMapHgt , To . x , To . y , To . Wdt , To . Hgt , iOffsX , iOffsY ) ;
2011-05-31 01:04:38 +00:00
FinishChange ( To ) ;
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
2011-05-31 01:04:38 +00:00
CSurface8 * C4Landscape : : CreateMap ( )
2010-02-09 19:09:32 +00:00
{
2011-05-31 01:04:38 +00:00
CSurface8 * sfcMap ;
int32_t iWidth = 0 , iHeight = 0 ;
// Create map surface
Game . C4S . Landscape . GetMapSize ( iWidth , iHeight , Game . StartupPlayerCount ) ;
if ( ! ( sfcMap = new CSurface8 ( iWidth , iHeight ) ) )
return NULL ;
// Fill sfcMap
C4MapCreator MapCreator ;
MapCreator . Create ( sfcMap ,
Game . C4S . Landscape , : : TextureMap ,
true , Game . StartupPlayerCount ) ;
return sfcMap ;
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
CSurface8 * C4Landscape : : CreateMapS2 ( C4Group & ScenFile )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// file present?
if ( ! ScenFile . AccessEntry ( C4CFN_DynLandscape ) ) return NULL ;
// create map creator
if ( ! pMapCreator )
pMapCreator = new C4MapCreatorS2 ( & Game . C4S . Landscape , & : : TextureMap , & : : MaterialMap , Game . StartupPlayerCount ) ;
// read file
pMapCreator - > ReadFile ( C4CFN_DynLandscape , & ScenFile ) ;
// render landscape
CSurface8 * sfc = pMapCreator - > Render ( NULL ) ;
// keep map creator until script callbacks have been done
return sfc ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
bool C4Landscape : : PostInitMap ( )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// map creator present?
if ( ! pMapCreator ) return true ;
// call scripts
pMapCreator - > ExecuteCallbacks ( MapZoom ) ;
// destroy map creator, if not needed later
if ( ! Game . C4S . Landscape . KeepMapCreator ) { delete pMapCreator ; pMapCreator = NULL ; }
// done, success
return true ;
2010-03-28 18:58:01 +00:00
}
2011-05-30 22:33:35 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++ Searching for features in the landscape +++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2011-05-31 01:04:38 +00:00
bool C4Landscape : : _PathFree ( int32_t x , int32_t y , int32_t x2 , int32_t y2 )
{
x / = 17 ; y / = 15 ; x2 / = 17 ; y2 / = 15 ;
while ( x ! = x2 & & y ! = y2 )
{
if ( PixCnt [ x * PixCntPitch + y ] )
return false ;
if ( x > x2 ) x - - ; else x + + ;
if ( y > y2 ) y - - ; else y + + ;
}
if ( x ! = x2 )
do
{
if ( PixCnt [ x * PixCntPitch + y ] )
return false ;
if ( x > x2 ) x - - ; else x + + ;
}
while ( x ! = x2 ) ;
else
while ( y ! = y2 )
{
if ( PixCnt [ x * PixCntPitch + y ] )
return false ;
if ( y > y2 ) y - - ; else y + + ;
}
return ! PixCnt [ x * PixCntPitch + y ] ;
}
int32_t C4Landscape : : GetMatHeight ( int32_t x , int32_t y , int32_t iYDir , int32_t iMat , int32_t iMax )
{
if ( iYDir > 0 )
{
iMax = Min < int32_t > ( iMax , Height - y ) ;
for ( int32_t i = 0 ; i < iMax ; i + + )
if ( _GetMat ( x , y + i ) ! = iMat )
return i ;
}
else
{
iMax = Min < int32_t > ( iMax , y + 1 ) ;
for ( int32_t i = 0 ; i < iMax ; i + + )
if ( _GetMat ( x , y - i ) ! = iMat )
return i ;
}
return iMax ;
}
2011-05-30 22:33:35 +00:00
// Nearest free above semi solid
2012-02-10 20:48:48 +00:00
bool AboveSemiSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cy1 = ry , cy2 = ry ;
2009-08-15 18:50:32 +00:00
bool UseUpwardsNextFree = false , UseDownwardsNextSolid = false ;
2009-05-08 13:28:41 +00:00
while ( ( cy1 > = 0 ) | | ( cy2 < GBackHgt ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
if ( cy1 > = 0 )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( GBackSemiSolid ( rx , cy1 ) ) UseUpwardsNextFree = true ;
else if ( UseUpwardsNextFree ) { ry = cy1 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Check downwards
if ( cy2 < GBackHgt )
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( ! GBackSemiSolid ( rx , cy2 ) ) UseDownwardsNextSolid = true ;
else if ( UseDownwardsNextSolid ) { ry = cy2 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Nearest free directly above solid
2012-02-10 20:48:48 +00:00
bool AboveSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cy1 = ry , cy2 = ry ;
while ( ( cy1 > = 0 ) | | ( cy2 < GBackHgt ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
if ( cy1 > = 0 )
if ( ! GBackSemiSolid ( rx , cy1 ) )
if ( GBackSolid ( rx , cy1 + 1 ) )
2009-08-15 18:50:32 +00:00
{ ry = cy1 ; return true ; }
2009-05-08 13:28:41 +00:00
// Check downwards
if ( cy2 + 1 < GBackHgt )
if ( ! GBackSemiSolid ( rx , cy2 ) )
if ( GBackSolid ( rx , cy2 + 1 ) )
2009-08-15 18:50:32 +00:00
{ ry = cy2 ; return true ; }
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Nearest free/semi above solid
2012-02-10 20:48:48 +00:00
bool SemiAboveSolid ( int32_t & rx , int32_t & ry )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cy1 = ry , cy2 = ry ;
while ( ( cy1 > = 0 ) | | ( cy2 < GBackHgt ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
if ( cy1 > = 0 )
if ( ! GBackSolid ( rx , cy1 ) )
if ( GBackSolid ( rx , cy1 + 1 ) )
2009-08-15 18:50:32 +00:00
{ ry = cy1 ; return true ; }
2009-05-08 13:28:41 +00:00
// Check downwards
if ( cy2 + 1 < GBackHgt )
if ( ! GBackSolid ( rx , cy2 ) )
if ( GBackSolid ( rx , cy2 + 1 ) )
2009-08-15 18:50:32 +00:00
{ ry = cy2 ; return true ; }
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
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 FindLiquidHeight ( int32_t cx , int32_t & ry , int32_t hgt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t cy1 = ry , cy2 = ry , rl1 = 0 , rl2 = 0 ;
while ( ( cy1 > = 0 ) | | ( cy2 < GBackHgt ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Check upwards
if ( cy1 > = 0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( GBackLiquid ( cx , cy1 ) )
2009-08-15 18:50:32 +00:00
{ rl1 + + ; if ( rl1 > = hgt ) { ry = cy1 + hgt / 2 ; return true ; } }
2009-05-08 13:28:41 +00:00
else rl1 = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Check downwards
if ( cy2 + 1 < GBackHgt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( GBackLiquid ( cx , cy2 ) )
2009-08-15 18:50:32 +00:00
{ rl2 + + ; if ( rl2 > = hgt ) { ry = cy2 - hgt / 2 ; return true ; } }
2009-05-08 13:28:41 +00:00
else rl2 = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Advance
cy1 - - ; cy2 + + ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-02 22:11:00 +00:00
bool FindTunnelHeight ( int32_t cx , int32_t & ry , int32_t hgt )
{
int32_t cy1 = ry , cy2 = ry , rl1 = 0 , rl2 = 0 ;
while ( ( cy1 > = 0 ) | | ( cy2 < GBackHgt ) )
{
// Check upwards
if ( cy1 > = 0 )
{
if ( GBackIFT ( cx , cy1 ) & & MatDensity ( GBackMat ( cx , cy1 ) ) < 25 )
{ rl1 + + ; if ( rl1 > = hgt ) { ry = cy1 + hgt / 2 ; return true ; } }
else rl1 = 0 ;
}
// Check downwards
if ( cy2 + 1 < GBackHgt )
{
if ( GBackIFT ( cx , cy2 ) & & MatDensity ( GBackMat ( cx , cy2 ) ) < 25 )
{ rl2 + + ; if ( rl2 > = hgt ) { ry = cy2 - hgt / 2 ; return true ; } }
else rl2 = 0 ;
}
// Advance
cy1 - - ; cy2 + + ;
}
return false ;
}
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid ground.
// Returns bottom center of surface space found.
2009-08-15 18:50:32 +00:00
bool FindSolidGround ( int32_t & rx , int32_t & ry , int32_t width )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fFound = false ;
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
if ( cx1 > = 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( AboveSolid ( cx1 , cy1 ) ) rl1 + + ; // Run okay
else rl1 = 0 ; // No run
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
if ( cx2 < GBackWdt ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( AboveSolid ( cx2 , cy2 ) ) rl2 + + ; // Run okay
else rl2 = 0 ; // No run
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
return fFound ;
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 FindSurfaceLiquid ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fFound = false ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 , cnt ;
2009-08-15 18:50:32 +00:00
bool lokay ;
2010-03-27 16:05:02 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) cx1 = - 1 ; // Abort left
else
2010-03-28 18:58:01 +00:00
{
for ( lokay = true , cnt = 0 ; cnt < height ; cnt + + ) if ( ! GBackLiquid ( cx1 , cy1 + 1 + cnt ) ) lokay = false ;
2009-05-08 13:28:41 +00:00
if ( lokay ) rl1 + + ; // Run okay
2010-03-27 16:05:02 +00:00
else rl1 = 0 ; // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
if ( cx2 < GBackWdt ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) cx2 = GBackWdt ; // Abort right
else
2010-03-28 18:58:01 +00:00
{
for ( lokay = true , cnt = 0 ; cnt < height ; cnt + + ) if ( ! GBackLiquid ( cx2 , cy2 + 1 + cnt ) ) lokay = false ;
2009-05-08 13:28:41 +00:00
if ( lokay ) rl2 + + ; // Run okay
2010-03-27 16:05:02 +00:00
else rl2 = 0 ; // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return fFound ;
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 FindLiquid ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
if ( cx1 > 0 )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( FindLiquidHeight ( cx1 , cy1 , height ) ) rl1 + + ;
else rl1 = 0 ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
if ( cx2 < GBackWdt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( FindLiquidHeight ( cx2 , cy2 , height ) ) rl2 + + ;
else rl2 = 0 ;
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; return true ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-10-02 22:11:00 +00:00
// Starting from rx/ry, searches for tunnel background
// Tunnel background == no sky && no semi/solid material (density < 25)
bool FindTunnel ( int32_t & rx , int32_t & ry , int32_t width , int32_t height )
{
int32_t cx1 , cx2 , cy1 , cy2 , rl1 = 0 , rl2 = 0 ;
for ( cx1 = cx2 = rx , cy1 = cy2 = ry ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
{
// Left search
if ( cx1 > 0 )
{
if ( FindTunnelHeight ( cx1 , cy1 , height ) ) rl1 + + ;
else rl1 = 0 ;
}
// Right search
if ( cx2 < GBackWdt )
{
if ( FindTunnelHeight ( cx2 , cy2 , height ) ) rl2 + + ;
else rl2 = 0 ;
}
// Check runs
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; return true ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; return true ; }
}
return false ;
}
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid ground. Extreme distances
// may not exceed hrange. Returns bottom center of surface found.
2009-08-15 18:50:32 +00:00
bool FindLevelGround ( int32_t & rx , int32_t & ry , int32_t width , int32_t hrange )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fFound = false ;
int32_t cx1 , cx2 , cy1 , cy2 , rh1 , rh2 , rl1 , rl2 ;
cx1 = cx2 = rx ; cy1 = cy2 = ry ;
rh1 = cy1 ; rh2 = cy2 ;
rl1 = rl2 = 0 ;
for ( cx1 - - , cx2 + + ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) cx1 = - 1 ; // Abort left
else
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( GBackSolid ( cx1 , cy1 + 1 ) & & ( Abs ( cy1 - rh1 ) < hrange ) )
rl1 + + ; // Run okay
else
{ rl1 = 0 ; rh1 = cy1 ; } // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
if ( cx2 < GBackWdt ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) cx2 = GBackWdt ; // Abort right
else
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( GBackSolid ( cx2 , cy2 + 1 ) & & ( Abs ( cy2 - rh2 ) < hrange ) )
rl2 + + ; // Run okay
else
{ rl2 = 0 ; rh2 = cy2 ; } // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs
if ( rl1 > = width ) { rx = cx1 + rl1 / 2 ; ry = cy1 ; fFound = true ; break ; }
if ( rl2 > = width ) { rx = cx2 - rl2 / 2 ; ry = cy2 ; fFound = true ; break ; }
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-30 22:33:35 +00:00
// Starting from rx/ry, searches for a width of solid level ground with
// structure clearance (category). Returns bottom center of surface found.
2009-08-15 18:50:32 +00:00
bool FindConSiteSpot ( int32_t & rx , int32_t & ry , int32_t wdt , int32_t hgt ,
2010-12-27 19:15:55 +00:00
int32_t Plane , int32_t hrange )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
bool fFound = false ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
// No hrange limit, use standard smooth surface limit
if ( hrange = = - 1 ) hrange = Max ( wdt / 4 , 5 ) ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
int32_t cx1 , cx2 , cy1 , cy2 , rh1 , rh2 , rl1 , rl2 ;
2009-05-08 13:28:41 +00:00
// Left offset starting position
cx1 = Min ( rx + wdt / 2 , GBackWdt - 1 ) ; cy1 = ry ;
// No good: use centered starting position
if ( ! AboveSemiSolid ( cx1 , cy1 ) ) { cx1 = Min < int32_t > ( rx , GBackWdt - 1 ) ; cy1 = ry ; }
// Right offset starting position
cx2 = Max ( rx - wdt / 2 , 0 ) ; cy2 = ry ;
// No good: use centered starting position
if ( ! AboveSemiSolid ( cx2 , cy2 ) ) { cx2 = Min < int32_t > ( rx , GBackWdt - 1 ) ; cy2 = ry ; }
2010-03-27 16:05:02 +00:00
rh1 = cy1 ; rh2 = cy2 ; rl1 = rl2 = 0 ;
2009-05-08 13:28:41 +00:00
2010-03-27 16:05:02 +00:00
for ( cx1 - - , cx2 + + ; ( cx1 > 0 ) | | ( cx2 < GBackWdt ) ; cx1 - - , cx2 + + )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
// Left search
if ( cx1 > 0 ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx1 , cy1 ) )
2009-05-08 13:28:41 +00:00
cx1 = - 1 ; // Abort left
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( GBackSolid ( cx1 , cy1 + 1 ) & & ( Abs ( cy1 - rh1 ) < hrange ) )
rl1 + + ; // Run okay
else
{ rl1 = 0 ; rh1 = cy1 ; } // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Right search
if ( cx2 < GBackWdt ) // Still going
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( ! AboveSemiSolid ( cx2 , cy2 ) )
2009-05-08 13:28:41 +00:00
cx2 = GBackWdt ; // Abort right
2010-03-27 16:05:02 +00:00
else
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
if ( GBackSolid ( cx2 , cy2 + 1 ) & & ( Abs ( cy2 - rh2 ) < hrange ) )
rl2 + + ; // Run okay
else
{ rl2 = 0 ; rh2 = cy2 ; } // No run
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check runs & object overlap
if ( rl1 > = wdt ) if ( cx1 > 0 )
2010-12-27 19:15:55 +00:00
if ( ! Game . OverlapObject ( cx1 , cy1 - hgt - 10 , wdt , hgt + 40 , Plane ) )
2010-03-28 18:58:01 +00:00
{ rx = cx1 + wdt / 2 ; ry = cy1 ; fFound = true ; break ; }
2010-03-27 16:05:02 +00:00
if ( rl2 > = wdt ) if ( cx2 < GBackWdt )
2010-12-27 19:15:55 +00:00
if ( ! Game . OverlapObject ( cx2 - wdt , cy2 - hgt - 10 , wdt , hgt + 40 , Plane ) )
2010-03-28 18:58:01 +00:00
{ rx = cx2 - wdt / 2 ; ry = cy2 ; fFound = true ; break ; }
}
2010-03-27 16:05:02 +00:00
if ( fFound ) AboveSemiSolid ( rx , ry ) ;
return fFound ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
// Returns false on any solid pix in path.
2009-05-08 13:28:41 +00:00
bool PathFreePix ( int32_t x , int32_t y , int32_t par )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
return ! GBackSolid ( x , y ) ;
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 PathFree ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 , int32_t * ix , int32_t * iy )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
return ForLine ( x1 , y1 , x2 , y2 , & PathFreePix , 0 , ix , iy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool PathFreeIgnoreVehiclePix ( int32_t x , int32_t y , int32_t par )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BYTE byPix = GBackPix ( x , y ) ;
2009-06-05 15:20:41 +00:00
return ! byPix | | ! DensitySolid ( : : Landscape . GetPixMat ( byPix ) ) | | : : Landscape . GetPixMat ( byPix ) = = MVehic ;
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 PathFreeIgnoreVehicle ( int32_t x1 , int32_t y1 , int32_t x2 , int32_t y2 , int32_t * ix , int32_t * iy )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
return ForLine ( x1 , y1 , x2 , y2 , & PathFreeIgnoreVehiclePix , 0 , ix , iy ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
int32_t TrajectoryDistance ( int32_t iFx , int32_t iFy , C4Real iXDir , C4Real iYDir , int32_t iTx , int32_t iTy )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t iClosest = Distance ( iFx , iFy , iTx , iTy ) ;
// Follow free trajectory, take closest point distance
2010-05-04 15:35:18 +00:00
C4Real cx = itofix ( iFx ) , cy = itofix ( iFy ) ;
2009-05-08 13:28:41 +00:00
int32_t cdis ;
while ( Inside ( fixtoi ( cx ) , 0 , GBackWdt - 1 ) & & Inside ( fixtoi ( cy ) , 0 , GBackHgt - 1 ) & & ! GBackSolid ( fixtoi ( cx ) , fixtoi ( cy ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
cdis = Distance ( fixtoi ( cx ) , fixtoi ( cy ) , iTx , iTy ) ;
if ( cdis < iClosest ) iClosest = cdis ;
cx + = iXDir ; cy + = iYDir ; iYDir + = GravAccel ;
}
2010-03-28 18:58:01 +00:00
return iClosest ;
}
2009-05-08 13:28:41 +00:00
const int32_t C4LSC_Throwing_MaxVertical = 50 ,
2011-05-30 22:33:35 +00:00
C4LSC_Throwing_MaxHorizontal = 60 ;
2009-05-08 13:28:41 +00:00
2010-05-04 15:35:18 +00:00
bool FindThrowingPosition ( int32_t iTx , int32_t iTy , C4Real fXDir , C4Real fYDir , int32_t iHeight , int32_t & rX , int32_t & rY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Start underneath throwing target
2010-03-28 18:58:01 +00:00
rX = iTx ; rY = iTy ; // improve: check from overhanging cliff
2009-08-15 18:50:32 +00:00
if ( ! SemiAboveSolid ( rX , rY ) ) return false ;
2009-05-08 13:28:41 +00:00
// Target too far above surface
2009-08-15 18:50:32 +00:00
if ( ! Inside ( rY - iTy , - C4LSC_Throwing_MaxVertical , + C4LSC_Throwing_MaxVertical ) ) return false ;
2009-05-08 13:28:41 +00:00
// Search in direction according to launch fXDir
int32_t iDir = + 1 ; if ( fXDir > 0 ) iDir = - 1 ;
// Move along surface
for ( int32_t cnt = 0 ; Inside < int32_t > ( rX , 0 , GBackWdt - 1 ) & & ( cnt < = C4LSC_Throwing_MaxHorizontal ) ; rX + = iDir , cnt + + )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Adjust to surface
2009-08-15 18:50:32 +00:00
if ( ! SemiAboveSolid ( rX , rY ) ) return false ;
2009-05-08 13:28:41 +00:00
// Check trajectory distance
int32_t itjd = TrajectoryDistance ( rX , rY - iHeight , fXDir , fYDir , iTx , iTy ) ;
// Hitting range: success
2009-08-15 18:50:32 +00:00
if ( itjd < = 2 ) return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Failure
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
const int32_t C4LSC_Closest_MaxRange = 200 ,
2011-05-30 22:33:35 +00:00
C4LSC_Closest_Step = 10 ;
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool FindClosestFree ( int32_t & rX , int32_t & rY , int32_t iAngle1 , int32_t iAngle2 ,
2010-03-28 18:58:01 +00:00
int32_t iExcludeAngle1 , int32_t iExcludeAngle2 )
{
2009-05-08 13:28:41 +00:00
int32_t iX , iY ;
for ( int32_t iR = C4LSC_Closest_Step ; iR < C4LSC_Closest_MaxRange ; iR + = C4LSC_Closest_Step )
for ( int32_t iAngle = iAngle1 ; iAngle < iAngle2 ; iAngle + = C4LSC_Closest_Step )
if ( ! Inside ( iAngle , iExcludeAngle1 , iExcludeAngle2 ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
iX = rX + fixtoi ( Sin ( itofix ( iAngle ) ) * iR ) ;
iY = rY - fixtoi ( Cos ( itofix ( iAngle ) ) * iR ) ;
if ( Inside < int32_t > ( iX , 0 , GBackWdt - 1 ) )
if ( Inside < int32_t > ( iY , 0 , GBackHgt - 1 ) )
if ( ! GBackSemiSolid ( iX , iY ) )
2009-08-15 18:50:32 +00:00
{ rX = iX ; rY = iY ; return true ; }
2010-03-28 18:58:01 +00:00
}
2009-08-15 18:50:32 +00:00
return false ;
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 ConstructionCheck ( C4PropList * PropList , int32_t iX , int32_t iY , C4Object * pByObj )
2010-03-28 18:58:01 +00:00
{
2009-04-12 12:04:28 +00:00
C4Def * ndef ;
// Check def
if ( ! ( ndef = PropList - > GetDef ( ) ) )
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_UNDEF " ) , PropList - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-04-12 12:04:28 +00:00
}
// Constructable?
if ( ! ndef - > Constructable )
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_NOCON " ) , ndef - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:04:28 +00:00
// Check area
int32_t rtx , rty , wdt , hgt ;
wdt = ndef - > Shape . Wdt ; hgt = ndef - > Shape . Hgt - ndef - > ConSizeOff ;
rtx = iX - wdt / 2 ; rty = iY - hgt ;
2009-07-21 14:46:39 +00:00
if ( : : Landscape . AreaSolidCount ( rtx , rty , wdt , hgt ) > ( wdt * hgt / 20 ) )
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
if ( pByObj ) GameMsgObjectError ( LoadResStr ( " IDS_OBJ_NOROOM " ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-07-21 14:46:39 +00:00
if ( : : Landscape . AreaSolidCount ( rtx , rty + hgt , wdt , 5 ) < ( wdt * 2 ) )
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
if ( pByObj ) GameMsgObjectError ( LoadResStr ( " IDS_OBJ_NOLEVEL " ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-04-12 12:04:28 +00:00
// Check other structures
C4Object * other ;
2010-12-27 19:15:55 +00:00
if ( ( other = Game . OverlapObject ( rtx , rty , wdt , hgt , ndef - > GetPlane ( ) ) ) )
2010-03-28 18:58:01 +00:00
{
2010-06-28 23:02:16 +00:00
if ( pByObj ) GameMsgObjectError ( FormatString ( LoadResStr ( " IDS_OBJ_NOOTHER " ) , other - > GetName ( ) ) . getData ( ) , pByObj ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-04-12 12:04:28 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Finds the next pixel position moving to desired slide.
bool C4Landscape : : FindMatPath ( int32_t & fx , int32_t & fy , int32_t ydir , int32_t mdens , int32_t mslide )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t cslide ;
bool fLeft = true , fRight = true ;
// One downwards
if ( GetDensity ( fx , fy + ydir ) < mdens ) { fy + = ydir ; return true ; }
// Find downwards slide path
for ( cslide = 1 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
{
// Check left
if ( fLeft )
{
if ( GetDensity ( fx - cslide , fy ) > = mdens ) // Left clogged
fLeft = false ;
else if ( GetDensity ( fx - cslide , fy + ydir ) < mdens ) // Left slide okay
{ fx - - ; return true ; }
}
// Check right
if ( fRight )
{
if ( GetDensity ( fx + cslide , fy ) > = mdens ) // Right clogged
fRight = false ;
else if ( GetDensity ( fx + cslide , fy + ydir ) < mdens ) // Right slide okay
{ fx + + ; return true ; }
}
}
return false ;
2010-03-28 18:58:01 +00:00
}
2009-06-12 18:52:21 +00:00
2011-05-31 01:04:38 +00:00
// Finds the closest immediate slide position.
bool C4Landscape : : FindMatSlide ( int32_t & fx , int32_t & fy , int32_t ydir , int32_t mdens , int32_t mslide )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
int32_t cslide ;
bool fLeft = true , fRight = true ;
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// One downwards
if ( GetDensity ( fx , fy + ydir ) < mdens ) { fy + = ydir ; return true ; }
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Find downwards slide path
for ( cslide = 1 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
{
// Check left
if ( fLeft )
{
if ( GetDensity ( fx - cslide , fy ) > = mdens & & GetDensity ( fx - cslide , fy + ydir ) > = mdens ) // Left clogged
fLeft = false ;
else if ( GetDensity ( fx - cslide , fy + ydir ) < mdens ) // Left slide okay
{ fx - = cslide ; fy + = ydir ; return true ; }
}
// Check right
if ( fRight )
{
if ( GetDensity ( fx + cslide , fy ) > = mdens & & GetDensity ( fx + cslide , fy + ydir ) > = mdens ) // Right clogged
fRight = false ;
else if ( GetDensity ( fx + cslide , fy + ydir ) < mdens ) // Right slide okay
{ fx + = cslide ; fy + = ydir ; return true ; }
}
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
return false ;
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
// Find closest point with density below mdens. Note this may return a point outside of the landscape,
// Assumption: There are no holes with smaller density inside of material with greater
// density.
bool C4Landscape : : FindMatPathPush ( int32_t & fx , int32_t & fy , int32_t mdens , int32_t mslide , bool liquid )
{
// Startpoint must be inside landscape
fx = BoundBy < int32_t > ( fx , 0 , Width - 1 ) ;
fy = BoundBy < int32_t > ( fy , 0 , Height - 1 ) ;
// Range to search, calculate bounds
const int32_t iPushRange = 500 ;
int32_t left = Max < int32_t > ( 0 , fx - iPushRange ) , right = Min < int32_t > ( Width - 1 , fx + iPushRange ) ,
top = Max < int32_t > ( 0 , fy - iPushRange ) , bottom = Min < int32_t > ( Height - 1 , fy + iPushRange ) ;
// Direction constants
const int8_t R = 0 , D = 1 , L = 2 , U = 3 ;
int8_t dir = 0 ;
int32_t x = fx , y = fy ;
// Get startpoint density
int32_t dens = GetDensity ( fx , fy ) ;
// Smaller density? We're done.
if ( dens < mdens )
return true ;
// Right density?
else if ( dens = = mdens )
{
// Find start point for border search
for ( int32_t i = 0 ; ; i + + )
if ( x - i - 1 < left | | GetDensity ( x - i - 1 , y ) ! = mdens )
{ x - = i ; dir = L ; break ; }
else if ( y - i - 1 < top | | GetDensity ( x , y - i - 1 ) ! = mdens )
{ y - = i ; dir = U ; break ; }
else if ( x + i + 1 > right | | GetDensity ( x + i + 1 , y ) ! = mdens )
{ x + = i ; dir = R ; break ; }
else if ( y + i + 1 > bottom | | GetDensity ( x , y + i + 1 ) ! = mdens )
{ y + = i ; dir = D ; break ; }
}
// Greater density
else
{
// Try to find a way out
int i = 1 ;
for ( ; i < iPushRange ; i + + )
if ( GetDensity ( x - i , y ) < = mdens )
{ x - = i ; dir = R ; break ; }
else if ( GetDensity ( x , y - i ) < = mdens )
{ y - = i ; dir = D ; break ; }
else if ( GetDensity ( x + i , y ) < = mdens )
{ x + = i ; dir = L ; break ; }
else if ( GetDensity ( x , y + i ) < = mdens )
{ y + = i ; dir = U ; break ; }
// Not found?
if ( i > = iPushRange ) return false ;
// Done?
if ( GetDensity ( x , y ) < mdens )
{
fx = x ; fy = y ;
return true ;
}
}
// Save startpoint of search
int32_t sx = x , sy = y , sdir = dir ;
// Best point so far
bool fGotBest = false ; int32_t bx = 0 , by = 0 , bdist = 0 ;
// Start searching
do
{
// We should always be in a material of same density
assert ( x > = left & & y > = top & & x < = right & & y < = bottom & & GetDensity ( x , y ) = = mdens ) ;
// Calc new position
int nx = x , ny = y ;
switch ( dir )
{
case R : nx + + ; break ;
case D : ny + + ; break ;
case L : nx - - ; break ;
case U : ny - - ; break ;
default : assert ( false ) ;
}
// In bounds?
bool fInBounds = ( nx > = left & & ny > = top & & nx < = right & & ny < = bottom ) ;
// Get density. Not this performs an SideOpen-check if outside landscape bounds.
int32_t dens = GetDensity ( nx , ny ) ;
// Flow possible?
if ( dens < mdens )
{
// Calculate "distance".
int32_t dist = Abs ( nx - fx ) + mslide * ( liquid ? fy - ny : Abs ( fy - ny ) ) ;
// New best point?
if ( ! fGotBest | | dist < bdist )
{
// Save it
bx = nx ; by = ny ; bdist = dist ; fGotBest = true ;
// Adjust borders: We can obviously safely ignore anything at greater distance
top = Max < int32_t > ( top , fy - dist / mslide - 1 ) ;
if ( ! liquid )
{
bottom = Min < int32_t > ( bottom , fy + dist / mslide + 1 ) ;
left = Max < int32_t > ( left , fx - dist - 1 ) ;
right = Min < int32_t > ( right , fx + dist + 1 ) ;
}
// Set new startpoint
sx = x ; sy = y ; sdir = dir ;
}
}
// Step?
if ( fInBounds & & dens = = mdens )
{
// New point
x = nx ; y = ny ;
// Turn left
( dir + = 3 ) % = 4 ;
}
// Otherwise: Turn right
else
+ + dir % = 4 ;
}
while ( x ! = sx | | y ! = sy | | dir ! = sdir ) ;
// Nothing found?
if ( ! fGotBest ) return false ;
// Return it
fx = bx ; fy = by ;
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
2011-05-31 01:04:38 +00:00
bool C4Landscape : : FindMatPathPull ( int32_t & fx , int32_t & fy , int32_t mdens , int32_t mslide , bool liquid )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// TODO
return true ;
}
int32_t C4Landscape : : AreaSolidCount ( int32_t x , int32_t y , int32_t wdt , int32_t hgt )
{
int32_t cx , cy , ascnt = 0 ;
for ( cy = y ; cy < y + hgt ; cy + + )
for ( cx = x ; cx < x + wdt ; cx + + )
if ( GBackSolid ( cx , cy ) )
ascnt + + ;
return ascnt ;
}
void C4Landscape : : FindMatTop ( int32_t mat , int32_t & x , int32_t & y )
{
int32_t mslide , cslide , tslide ; // tslide 0 none 1 left 2 right
bool fLeft , fRight ;
if ( ! MatValid ( mat ) ) return ;
mslide = : : MaterialMap . Map [ mat ] . MaxSlide ;
do
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Find upwards slide
fLeft = true ; fRight = true ; tslide = 0 ;
for ( cslide = 0 ; ( cslide < = mslide ) & & ( fLeft | | fRight ) ; cslide + + )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// Left
if ( fLeft )
{
if ( GetMat ( x - cslide , y ) ! = mat ) fLeft = false ;
else if ( GetMat ( x - cslide , y - 1 ) = = mat ) { tslide = 1 ; break ; }
}
// Right
if ( fRight )
{
if ( GetMat ( x + cslide , y ) ! = mat ) fRight = false ;
else if ( GetMat ( x + cslide , y - 1 ) = = mat ) { tslide = 2 ; break ; }
}
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
// Slide
if ( tslide = = 1 ) { x - = cslide ; y - - ; }
if ( tslide = = 2 ) { x + = cslide ; y - - ; }
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
while ( tslide ) ;
2010-03-28 18:58:01 +00:00
}
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++++++++++++ Editor mode (draw landscape with brush)+++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : SetMode ( int32_t iMode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Invalid mode
2009-08-15 18:50:32 +00:00
if ( ! Inside < int32_t > ( iMode , C4LSC_Dynamic , C4LSC_Exact ) ) return false ;
2009-05-08 13:28:41 +00:00
// Set mode
Mode = iMode ;
// 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
bool C4Landscape : : GetMapColorIndex ( const char * szMaterial , const char * szTexture , bool fIFT , BYTE & rbyCol )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Sky
if ( SEqual ( szMaterial , C4TLS_MatSky ) )
rbyCol = 0 ;
// Material-Texture
else
2010-03-28 18:58:01 +00:00
{
2009-08-15 18:50:32 +00:00
if ( ! ( rbyCol = : : TextureMap . GetIndex ( szMaterial , szTexture ) ) ) return false ;
2009-05-08 13:28:41 +00:00
if ( fIFT ) rbyCol + = IFT ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Found
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
bool C4Landscape : : DrawBrush ( int32_t iX , int32_t iY , int32_t iGrade , const char * szMaterial , const char * szTexture , bool fIFT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BYTE byCol ;
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
if ( ! GetMapColorIndex ( szMaterial , szTexture , fIFT , byCol ) ) return false ;
// Get material shape size
int32_t mat = PixCol2Mat ( byCol ) ;
int32_t shape_wdt = 0 , shape_hgt = 0 ;
if ( mat > = 0 & & MaterialMap . Map [ mat ] . CustomShape )
{
shape_wdt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_width / MapZoom ;
shape_hgt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_height / MapZoom ;
}
// Draw
2009-05-08 13:28:41 +00:00
switch ( Mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2010-03-28 18:58:01 +00:00
case C4LSC_Dynamic :
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2010-03-28 18:58:01 +00:00
case C4LSC_Static :
// Draw to map
int32_t iRadius ; iRadius = Max < int32_t > ( 2 * iGrade / MapZoom , 1 ) ;
if ( iRadius = = 1 ) { if ( Map ) Map - > SetPix ( iX / MapZoom , iY / MapZoom , byCol ) ; }
else Map - > Circle ( iX / MapZoom , iY / MapZoom , iRadius , byCol ) ;
// Update landscape
2011-07-16 19:50:49 +00:00
MapToLandscape ( Map , iX / MapZoom - iRadius - 1 - shape_wdt , iY / MapZoom - iRadius - 1 - shape_hgt , 2 * iRadius + 2 + shape_wdt * 2 , 2 * iRadius + 2 + shape_hgt * 2 ) ;
2010-03-28 18:58:01 +00:00
SetMapChanged ( ) ;
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2010-03-28 18:58:01 +00:00
case C4LSC_Exact :
C4Rect BoundingBox ( iX - iGrade - 1 , iY - iGrade - 1 , iGrade * 2 + 2 , iGrade * 2 + 2 ) ;
// Draw to landscape
PrepareChange ( BoundingBox ) ;
Surface8 - > Circle ( iX , iY , iGrade , byCol ) ;
FinishChange ( BoundingBox ) ;
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
BYTE DrawLineCol ;
bool C4Landscape : : DrawLineLandscape ( int32_t iX , int32_t iY , int32_t iGrade )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:20:41 +00:00
: : Landscape . Surface8 - > Circle ( iX , iY , iGrade , DrawLineCol ) ;
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
bool DrawLineMap ( int32_t iX , int32_t iY , int32_t iRadius )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:20:41 +00:00
if ( iRadius = = 1 ) { if ( : : Landscape . Map ) : : Landscape . Map - > SetPix ( iX , iY , DrawLineCol ) ; }
else : : Landscape . Map - > Circle ( iX , iY , iRadius , DrawLineCol ) ;
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
bool C4Landscape : : DrawLine ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iGrade , const char * szMaterial , const char * szTexture , bool fIFT )
2010-03-28 18:58:01 +00:00
{
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
if ( ! GetMapColorIndex ( szMaterial , szTexture , fIFT , DrawLineCol ) ) return false ;
// Get material shape size
int32_t mat = PixCol2Mat ( DrawLineCol ) ;
int32_t shape_wdt = 0 , shape_hgt = 0 ;
if ( mat > = 0 & & MaterialMap . Map [ mat ] . CustomShape )
{
shape_wdt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_width / MapZoom ;
shape_hgt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_height / MapZoom ;
}
// Draw
2009-05-08 13:28:41 +00:00
switch ( Mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2010-03-28 18:58:01 +00:00
case C4LSC_Dynamic :
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2010-03-28 18:58:01 +00:00
case C4LSC_Static :
// Draw to map
int32_t iRadius ; iRadius = Max < int32_t > ( 2 * iGrade / MapZoom , 1 ) ;
iX1 / = MapZoom ; iY1 / = MapZoom ; iX2 / = MapZoom ; iY2 / = MapZoom ;
ForLine ( iX1 , iY1 , iX2 , iY2 , & DrawLineMap , iRadius ) ;
// Update landscape
int32_t iUpX , iUpY , iUpWdt , iUpHgt ;
iUpX = Min ( iX1 , iX2 ) - iRadius - 1 ; iUpY = Min ( iY1 , iY2 ) - iRadius - 1 ;
iUpWdt = Abs ( iX2 - iX1 ) + 2 * iRadius + 2 ; iUpHgt = Abs ( iY2 - iY1 ) + 2 * iRadius + 2 ;
2011-07-16 19:50:49 +00:00
MapToLandscape ( Map , iUpX - shape_wdt , iUpY - shape_hgt , iUpWdt + shape_wdt * 2 , iUpHgt + shape_hgt * 2 ) ;
2010-03-28 18:58:01 +00:00
SetMapChanged ( ) ;
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2010-03-28 18:58:01 +00:00
case C4LSC_Exact :
// Set texture pattern & get material color
C4Rect BoundingBox ( iX1 - iGrade , iY1 - iGrade , iGrade * 2 + 1 , iGrade * 2 + 1 ) ;
BoundingBox . Add ( C4Rect ( iX2 - iGrade , iY2 - iGrade , iGrade * 2 + 1 , iGrade * 2 + 1 ) ) ;
// Draw to landscape
PrepareChange ( BoundingBox ) ;
ForLine ( iX1 , iY1 , iX2 , iY2 , & DrawLineLandscape , iGrade ) ;
FinishChange ( BoundingBox ) ;
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : DrawBox ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iGrade , const char * szMaterial , const char * szTexture , bool fIFT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// get upper-left/lower-right - corners
int32_t iX0 = Min ( iX1 , iX2 ) ; int32_t iY0 = Min ( iY1 , iY2 ) ;
iX2 = Max ( iX1 , iX2 ) ; iY2 = Max ( iY1 , iY2 ) ; iX1 = iX0 ; iY1 = iY0 ;
BYTE byCol ;
2011-07-16 19:50:49 +00:00
// Get map color index by material-texture
if ( ! GetMapColorIndex ( szMaterial , szTexture , fIFT , byCol ) ) return false ;
// Get material shape size
int32_t mat = PixCol2Mat ( byCol ) ;
int32_t shape_wdt = 0 , shape_hgt = 0 ;
if ( mat > = 0 & & MaterialMap . Map [ mat ] . CustomShape )
{
shape_wdt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_width / MapZoom ;
shape_hgt = MaterialMap . Map [ mat ] . CustomShape - > max_poly_height / MapZoom ;
}
// Draw
2009-05-08 13:28:41 +00:00
switch ( Mode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Dynamic: ignore
2010-03-28 18:58:01 +00:00
case C4LSC_Dynamic :
break ;
2009-05-08 13:28:41 +00:00
// Static: draw to map by material-texture-index, chunk-o-zoom to landscape
2010-03-28 18:58:01 +00:00
case C4LSC_Static :
// Draw to map
iX1 / = MapZoom ; iY1 / = MapZoom ; iX2 / = MapZoom ; iY2 / = MapZoom ;
Map - > Box ( iX1 , iY1 , iX2 , iY2 , byCol ) ;
// Update landscape
2011-07-16 19:50:49 +00:00
MapToLandscape ( Map , iX1 - 1 - shape_wdt , iY1 - 1 - shape_hgt , iX2 - iX1 + 3 + shape_wdt * 2 , iY2 - iY1 + 3 + shape_hgt * 2 ) ;
2010-03-28 18:58:01 +00:00
SetMapChanged ( ) ;
break ;
2009-05-08 13:28:41 +00:00
// Exact: draw directly to landscape by color & pattern
2010-03-28 18:58:01 +00:00
case C4LSC_Exact :
C4Rect BoundingBox ( iX1 , iY1 , iX2 - iX1 + 1 , iY2 - iY1 + 1 ) ;
// Draw to landscape
PrepareChange ( BoundingBox ) ;
Surface8 - > Box ( iX1 , iY1 , iX2 , iY2 , byCol ) ;
FinishChange ( BoundingBox ) ;
break ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : DrawChunks ( int32_t tx , int32_t ty , int32_t wdt , int32_t hgt , int32_t icntx , int32_t icnty , const char * szMaterial , const char * szTexture , bool bIFT )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
BYTE byColor ;
2009-08-15 18:50:32 +00:00
if ( ! GetMapColorIndex ( szMaterial , szTexture , bIFT , byColor ) ) return false ;
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
int32_t iMaterial = : : MaterialMap . Get ( szMaterial ) ; if ( ! MatValid ( iMaterial ) ) return false ;
2009-05-08 13:28:41 +00:00
C4Rect BoundingBox ( tx - 5 , ty - 5 , wdt + 10 , hgt + 10 ) ;
PrepareChange ( BoundingBox ) ;
// assign clipper
Surface8 - > Clip ( BoundingBox . x , BoundingBox . y , BoundingBox . x + BoundingBox . Wdt , BoundingBox . y + BoundingBox . Hgt ) ;
2011-10-03 14:30:18 +00:00
pDraw - > NoPrimaryClipper ( ) ;
2009-05-08 13:28:41 +00:00
// draw all chunks
int32_t x , y ;
2010-03-28 18:58:01 +00:00
for ( x = 0 ; x < icntx ; x + + )
for ( y = 0 ; y < icnty ; y + + )
2009-06-05 18:46:03 +00:00
DrawChunk ( tx + wdt * x / icntx , ty + hgt * y / icnty , wdt / icntx , hgt / icnty , byColor , : : MaterialMap . Map [ iMaterial ] . MapChunkType , Random ( 1000 ) ) ;
2009-05-08 13:28:41 +00:00
// remove clipper
Surface8 - > NoClip ( ) ;
FinishChange ( BoundingBox ) ;
// success
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
2011-05-30 22:33:35 +00:00
C4Rect C4Landscape : : getBoundingBox ( int * vtcs , int length ) const
{
2011-08-14 22:24:22 +00:00
C4Rect BoundingBox ( vtcs [ 0 ] , vtcs [ 1 ] , 1 , 1 ) ;
for ( int32_t i = 2 ; i + 1 < length ; i + = 2 )
2011-05-30 22:33:35 +00:00
{
2011-08-14 22:24:22 +00:00
BoundingBox . Add ( C4Rect ( vtcs [ i ] , vtcs [ i + 1 ] , 1 , 1 ) ) ;
2011-05-30 22:33:35 +00:00
}
return BoundingBox ;
}
2011-05-29 20:37:40 +00:00
bool C4Landscape : : DrawPolygon ( int * vtcs , int length , const char * szMaterial , bool fIFT , bool fDrawBridge )
2010-02-09 19:09:32 +00:00
{
2011-05-29 20:37:40 +00:00
if ( length < 6 ) return false ;
if ( length % 2 = = 1 ) return false ;
2009-05-08 13:28:41 +00:00
// get texture
2009-06-05 15:09:54 +00:00
int32_t iMatTex = : : TextureMap . GetIndexMatTex ( szMaterial ) ;
2010-03-28 18:58:01 +00:00
if ( ! iMatTex ) return false ;
2010-02-09 19:09:32 +00:00
// do bridging?
uint8_t * conversion_map = NULL ;
if ( fDrawBridge )
{
int32_t iMat = GetPixMat ( iMatTex ) ;
conversion_map = GetBridgeMatConversion ( iMat ) ;
}
2011-05-29 20:37:40 +00:00
// prepare pixel count update
2011-05-30 22:33:35 +00:00
C4Rect BoundingBox = getBoundingBox ( vtcs , length ) ;
2011-05-29 20:37:40 +00:00
// draw polygon
PrepareChange ( BoundingBox ) ;
2011-05-30 22:33:35 +00:00
ForPolygon ( vtcs , length / 2 , NULL , NULL , MatTex2PixCol ( iMatTex ) + ( fIFT ? IFT : 0 ) , conversion_map ) ;
2011-05-29 20:37:40 +00:00
FinishChange ( BoundingBox ) ;
return true ;
}
2011-05-31 01:04:38 +00:00
uint8_t * C4Landscape : : GetBridgeMatConversion ( int for_material )
{
// safety
if ( for_material < 0 | | for_material > = MaterialMap . Num ) return NULL ;
// query map. create if not done yet
uint8_t * conv_map = BridgeMatConversion [ for_material ] ;
if ( ! conv_map )
{
conv_map = new uint8_t [ 256 ] ;
for ( int32_t i = 0 ; i < 256 ; + + i )
{
if ( ( MatDensity ( for_material ) > GetPixDensity ( i ) )
| | ( ( MatDensity ( for_material ) = = GetPixDensity ( i ) ) & & ( MatDigFree ( for_material ) < = MatDigFree ( GetPixMat ( i ) ) ) ) )
{
// bridge pixel OK here. change pixel; keep IFT.
conv_map [ i ] = ( i & IFT ) + Mat2PixColDefault ( for_material ) ;
}
else
{
// bridge pixel not OK - keep current pixel
conv_map [ i ] = i ;
}
}
BridgeMatConversion [ for_material ] = conv_map ;
}
return conv_map ;
}
2011-05-29 20:37:40 +00:00
bool C4Landscape : : DrawQuad ( int32_t iX1 , int32_t iY1 , int32_t iX2 , int32_t iY2 , int32_t iX3 , int32_t iY3 , int32_t iX4 , int32_t iY4 , const char * szMaterial , bool fIFT , bool fDrawBridge )
{
2009-05-08 13:28:41 +00:00
// set vertices
2011-05-29 20:37:40 +00:00
int32_t vtcs [ 8 ] ;
2009-05-08 13:28:41 +00:00
vtcs [ 0 ] = iX1 ; vtcs [ 1 ] = iY1 ;
vtcs [ 2 ] = iX2 ; vtcs [ 3 ] = iY2 ;
vtcs [ 4 ] = iX3 ; vtcs [ 5 ] = iY3 ;
vtcs [ 6 ] = iX4 ; vtcs [ 7 ] = iY4 ;
2011-05-29 20:37:40 +00:00
return DrawPolygon ( vtcs , 8 , szMaterial , fIFT , fDrawBridge ) ;
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
BYTE C4Landscape : : GetMapIndex ( int32_t iX , int32_t iY )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ! Map ) return 0 ;
return Map - > GetPix ( iX , iY ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : PrepareChange ( C4Rect BoundingBox )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// move solidmasks out of the way
C4Rect SolidMaskRect = BoundingBox ;
if ( pLandscapeRender )
SolidMaskRect = pLandscapeRender - > GetAffectedRect ( pLandscapeRender - > GetAffectedRect ( SolidMaskRect ) ) ;
for ( C4SolidMask * pSolid = C4SolidMask : : Last ; pSolid ; pSolid = pSolid - > Prev )
{
pSolid - > RemoveTemporary ( SolidMaskRect ) ;
}
UpdateMatCnt ( BoundingBox , false ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : FinishChange ( C4Rect BoundingBox )
2010-03-28 18:58:01 +00:00
{
2011-05-31 01:04:38 +00:00
// update render
if ( pLandscapeRender )
pLandscapeRender - > Update ( BoundingBox , this ) ;
UpdateMatCnt ( BoundingBox , true ) ;
// Restore Solidmasks
C4Rect SolidMaskRect = BoundingBox ;
if ( pLandscapeRender )
SolidMaskRect = pLandscapeRender - > GetAffectedRect ( pLandscapeRender - > GetAffectedRect ( SolidMaskRect ) ) ;
for ( C4SolidMask * pSolid = C4SolidMask : : First ; pSolid ; pSolid = pSolid - > Next )
2009-05-08 13:28:41 +00:00
{
2011-05-31 01:04:38 +00:00
pSolid - > Repair ( SolidMaskRect ) ;
2010-03-27 16:05:02 +00:00
}
2011-05-31 01:04:38 +00:00
C4SolidMask : : CheckConsistency ( ) ;
UpdatePixCnt ( BoundingBox ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* ++++++++++++++++++ Functions for Script interface +++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2012-02-10 20:48:48 +00:00
bool C4Landscape : : DrawMap ( int32_t iX , int32_t iY , int32_t iWdt , int32_t iHgt , const char * szMapDef , bool ignoreSky )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2009-08-15 18:50:32 +00:00
if ( ! szMapDef ) return false ;
2009-05-08 13:28:41 +00:00
// clip to landscape size
2009-08-15 18:50:32 +00:00
if ( ! ClipRect ( iX , iY , iWdt , iHgt ) ) return false ;
2009-05-08 13:28:41 +00:00
// get needed map size
int32_t iMapWdt = ( iWdt - 1 ) / MapZoom + 1 ;
int32_t iMapHgt = ( iHgt - 1 ) / MapZoom + 1 ;
C4SLandscape FakeLS = Game . C4S . Landscape ;
FakeLS . MapWdt . Set ( iMapWdt , 0 , iMapWdt , iMapWdt ) ;
FakeLS . MapHgt . Set ( iMapHgt , 0 , iMapHgt , iMapHgt ) ;
// create map creator
2009-06-05 18:46:03 +00:00
C4MapCreatorS2 MapCreator ( & FakeLS , & : : TextureMap , & : : MaterialMap , Game . StartupPlayerCount ) ;
2009-05-08 13:28:41 +00:00
// read file
MapCreator . ReadScript ( szMapDef ) ;
// render map
CSurface8 * sfcMap = MapCreator . Render ( NULL ) ;
2009-08-15 18:50:32 +00:00
if ( ! sfcMap ) return false ;
2009-05-08 13:28:41 +00:00
// map it to the landscape
2012-02-10 20:48:48 +00:00
bool fSuccess = MapToLandscape ( sfcMap , 0 , 0 , iMapWdt , iMapHgt , iX , iY , ignoreSky ) ;
2009-05-08 13:28:41 +00:00
// cleanup
delete sfcMap ;
// return whether successful
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2012-02-10 20:48:48 +00:00
bool C4Landscape : : DrawDefMap ( int32_t iX , int32_t iY , int32_t iWdt , int32_t iHgt , const char * szMapDef , bool ignoreSky )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// safety
2009-08-15 18:50:32 +00:00
if ( ! szMapDef | | ! pMapCreator ) return false ;
2009-05-08 13:28:41 +00:00
// clip to landscape size
2009-08-15 18:50:32 +00:00
if ( ! ClipRect ( iX , iY , iWdt , iHgt ) ) return false ;
2009-05-08 13:28:41 +00:00
// get needed map size
int32_t iMapWdt = ( iWdt - 1 ) / MapZoom + 1 ;
int32_t iMapHgt = ( iHgt - 1 ) / MapZoom + 1 ;
2009-08-15 18:50:32 +00:00
bool fSuccess = false ;
2009-05-08 13:28:41 +00:00
// render map
C4MCMap * pMap = pMapCreator - > GetMap ( szMapDef ) ;
2009-08-15 18:50:32 +00:00
if ( ! pMap ) return false ;
2009-05-08 13:28:41 +00:00
pMap - > SetSize ( iMapWdt , iMapHgt ) ;
CSurface8 * sfcMap = pMapCreator - > Render ( szMapDef ) ;
if ( sfcMap )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// map to landscape
2012-02-10 20:48:48 +00:00
fSuccess = MapToLandscape ( sfcMap , 0 , 0 , iMapWdt , iMapHgt , iX , iY , ignoreSky ) ;
2009-05-08 13:28:41 +00:00
// cleanup
delete sfcMap ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done
return fSuccess ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Landscape : : ClipRect ( int32_t & rX , int32_t & rY , int32_t & rWdt , int32_t & rHgt )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// clip by bounds
if ( rX < 0 ) { rWdt + = rX ; rX = 0 ; }
if ( rY < 0 ) { rHgt + = rY ; rY = 0 ; }
int32_t iOver ;
iOver = rX + rWdt - Width ; if ( iOver > 0 ) { rWdt - = iOver ; }
iOver = rY + rHgt - Height ; if ( iOver > 0 ) { rHgt - = iOver ; }
// anything left inside the bounds?
return rWdt > 0 & & rHgt > 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Landscape : : ReplaceMapColor ( BYTE iOldIndex , BYTE iNewIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// find every occurance of iOldIndex in map; replace it by new index
if ( ! Map ) return false ;
int iPitch , iMapWdt , iMapHgt ;
BYTE * pMap = Map - > Bits ;
iMapWdt = Map - > Wdt ;
iMapHgt = Map - > Hgt ;
iPitch = Map - > Pitch ;
if ( ! pMap ) return false ;
for ( int32_t y = 0 ; y < iMapHgt ; + + y )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
for ( int32_t x = 0 ; x < iMapWdt ; + + x )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ( * pMap & 0x7f ) = = iOldIndex )
* pMap = ( * pMap & 0x80 ) + iNewIndex ;
+ + pMap ;
}
2010-03-28 18:58:01 +00:00
pMap + = iPitch - iMapWdt ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
return true ;
}
2009-05-08 13:28:41 +00:00
2009-08-15 18:50:32 +00:00
bool C4Landscape : : SetTextureIndex ( const char * szMatTex , BYTE iNewIndex , bool fInsert )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
if ( ( ( ! szMatTex | | ! * szMatTex ) & & ! fInsert ) | | ! Inside < int > ( iNewIndex , 0x01 , 0x7f ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Cannot insert new texture %s to index %d: Invalid parameters. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// get last mat index - returns zero for not found (valid for insertion mode)
StdStrBuf Material , Texture ;
Material . CopyUntil ( szMatTex , ' - ' ) ; Texture . Copy ( SSearch ( szMatTex , " - " ) ) ;
2009-08-15 18:50:32 +00:00
BYTE iOldIndex = ( szMatTex & & * szMatTex ) ? : : TextureMap . GetIndex ( Material . getData ( ) , Texture . getData ( ) , false ) : 0 ;
2009-05-08 13:28:41 +00:00
// insertion mode?
if ( fInsert )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// there must be room to move up to
BYTE byLastMoveIndex = C4M_MaxTexIndex - 1 ;
2009-06-05 15:09:54 +00:00
while ( : : TextureMap . GetEntry ( byLastMoveIndex ) )
2009-05-08 13:28:41 +00:00
if ( - - byLastMoveIndex = = iNewIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Cannot insert new texture %s to index %d: No room for insertion. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// then move up all other textures first
// could do this in one loop, but it's just a developement call anyway, so move one index at a time
while ( - - byLastMoveIndex > = iNewIndex )
2009-06-05 15:09:54 +00:00
if ( : : TextureMap . GetEntry ( byLastMoveIndex ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ReplaceMapColor ( byLastMoveIndex , byLastMoveIndex + 1 ) ;
2009-06-05 15:09:54 +00:00
: : TextureMap . MoveIndex ( byLastMoveIndex , byLastMoveIndex + 1 ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// new insertion desired?
if ( szMatTex & & * szMatTex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// move from old or create new
if ( iOldIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
ReplaceMapColor ( iOldIndex , iNewIndex ) ;
2009-06-05 15:09:54 +00:00
: : TextureMap . MoveIndex ( iOldIndex , iNewIndex ) ;
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
{
2009-05-08 13:28:41 +00:00
StdStrBuf Material , Texture ;
Material . CopyUntil ( szMatTex , ' - ' ) ; Texture . Copy ( SSearch ( szMatTex , " - " ) ) ;
// new insertion
2009-06-05 15:09:54 +00:00
if ( ! : : TextureMap . AddEntry ( iNewIndex , Material . getData ( ) , Texture . getData ( ) ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
LogF ( " Cannot insert new texture %s to index %d: Texture map entry error " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// done, success
return true ;
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
{
2009-05-08 13:28:41 +00:00
// new index must not be occupied
const C4TexMapEntry * pOld ;
2009-06-05 15:09:54 +00:00
if ( ( pOld = : : TextureMap . GetEntry ( iNewIndex ) ) & & ! pOld - > isNull ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Cannot move texture %s to index %d: Index occupied by %s-%s. " , ( const char * ) szMatTex , ( int ) iNewIndex , pOld - > GetMaterialName ( ) , pOld - > GetTextureName ( ) ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// must only move existing textures
if ( ! iOldIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
DebugLogF ( " Cannot move texture %s to index %d: Texture not found. " , ( const char * ) szMatTex , ( int ) iNewIndex ) ;
2009-08-15 18:50:32 +00:00
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// update map
ReplaceMapColor ( iOldIndex , iNewIndex ) ;
// change to new index in texmap
2009-06-05 15:09:54 +00:00
: : TextureMap . MoveIndex ( iOldIndex , iNewIndex ) ;
2009-05-08 13:28:41 +00:00
// done, success
2009-08-15 18:50:32 +00:00
return true ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2011-05-31 01:04:38 +00:00
void C4Landscape : : RemoveUnusedTexMapEntries ( )
{
// check usage in landscape
bool fTexUsage [ 128 ] ;
int32_t iMatTex ;
for ( iMatTex = 0 ; iMatTex < 128 ; + + iMatTex ) fTexUsage [ iMatTex ] = false ;
for ( int32_t y = 0 ; y < Height ; + + y )
for ( int32_t x = 0 ; x < Width ; + + x )
fTexUsage [ Surface8 - > GetPix ( x , y ) & 0x7f ] = true ;
// check usage by materials
for ( int32_t iMat = 0 ; iMat < : : MaterialMap . Num ; + + iMat )
{
C4Material * pMat = : : MaterialMap . Map + iMat ;
if ( pMat - > BlastShiftTo > = 0 ) fTexUsage [ pMat - > BlastShiftTo & 0x7f ] = true ;
if ( pMat - > BelowTempConvertTo > = 0 ) fTexUsage [ pMat - > BelowTempConvertTo & 0x7f ] = true ;
if ( pMat - > AboveTempConvertTo > = 0 ) fTexUsage [ pMat - > AboveTempConvertTo & 0x7f ] = true ;
if ( pMat - > DefaultMatTex > = 0 ) fTexUsage [ pMat - > DefaultMatTex & 0x7f ] = true ;
}
// remove unused
for ( iMatTex = 1 ; iMatTex < C4M_MaxTexIndex ; + + iMatTex )
if ( ! fTexUsage [ iMatTex ] )
: : TextureMap . RemoveEntry ( iMatTex ) ;
// flag rewrite
: : TextureMap . fEntriesAdded = true ;
}
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++ Update functions ++++++++++++++++++++++++++++ */
/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
2009-05-08 13:28:41 +00:00
void C4Landscape : : HandleTexMapUpdate ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Pixel maps must be update
UpdatePixMaps ( ) ;
// Update landscape palette
Mat2Pal ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : UpdatePixMaps ( )
2010-02-09 19:09:32 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t i ;
2010-03-28 18:58:01 +00:00
for ( i = 0 ; i < 256 ; i + + ) Pix2Mat [ i ] = PixCol2Mat ( i ) ;
for ( i = 0 ; i < 256 ; i + + ) Pix2Dens [ i ] = MatDensity ( Pix2Mat [ i ] ) ;
for ( i = 0 ; i < 256 ; i + + ) Pix2Place [ i ] = MatValid ( Pix2Mat [ i ] ) ? : : MaterialMap . Map [ Pix2Mat [ i ] ] . Placement : 0 ;
2009-05-08 13:28:41 +00:00
Pix2Place [ 0 ] = 0 ;
2010-02-09 19:09:32 +00:00
// clear bridge mat conversion buffers
for ( int32_t i = 0 ; i < C4MaxMaterial ; + + i )
{
delete [ ] BridgeMatConversion [ i ] ;
BridgeMatConversion [ i ] = NULL ;
2009-05-08 13:28:41 +00:00
}
2010-02-09 19:09:32 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4Landscape : : Mat2Pal ( )
2010-03-28 18:58:01 +00:00
{
if ( ! Surface8 ) return false ;
2009-05-08 13:28:41 +00:00
// set landscape pal
int32_t tex , rgb ;
for ( tex = 0 ; tex < C4M_MaxTexIndex ; tex + + )
2010-03-28 18:58:01 +00:00
{
2009-06-05 15:09:54 +00:00
const C4TexMapEntry * pTex = : : TextureMap . GetEntry ( tex ) ;
2010-03-28 18:58:01 +00:00
if ( ! pTex | | pTex - > isNull ( ) )
2009-05-08 13:28:41 +00:00
continue ;
// colors
2009-07-24 21:50:04 +00:00
DWORD dwPix = pTex - > GetPattern ( ) . PatternClr ( 0 , 0 ) ;
2012-08-15 22:45:27 +00:00
Surface8 - > pPal - > Colors [ MatTex2PixCol ( tex ) ] = dwPix ;
Surface8 - > pPal - > Colors [ MatTex2PixCol ( tex ) + IFT ] = dwPix ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// success
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : UpdatePixCnt ( const C4Rect & Rect , bool fCheck )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
int32_t PixCntWidth = ( Width + 16 ) / 17 ;
2010-03-28 18:58:01 +00:00
for ( int32_t y = Max < int32_t > ( 0 , Rect . y / 15 ) ; y < Min < int32_t > ( PixCntPitch , ( Rect . y + Rect . Hgt + 14 ) / 15 ) ; y + + )
for ( int32_t x = Max < int32_t > ( 0 , Rect . x / 17 ) ; x < Min < int32_t > ( PixCntWidth , ( Rect . x + Rect . Wdt + 16 ) / 17 ) ; x + + )
{
2009-05-08 13:28:41 +00:00
int iCnt = 0 ;
2010-03-28 18:58:01 +00:00
for ( int32_t x2 = x * 17 ; x2 < Min < int32_t > ( x * 17 + 17 , Width ) ; x2 + + )
for ( int32_t y2 = y * 15 ; y2 < Min < int32_t > ( y * 15 + 15 , Height ) ; y2 + + )
if ( _GetDensity ( x2 , y2 ) )
2009-05-08 13:28:41 +00:00
iCnt + + ;
2010-03-28 18:58:01 +00:00
if ( fCheck )
2009-05-08 13:28:41 +00:00
assert ( iCnt = = PixCnt [ x * PixCntPitch + y ] ) ;
PixCnt [ x * PixCntPitch + y ] = iCnt ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
void C4Landscape : : UpdateMatCnt ( C4Rect Rect , bool fPlus )
2010-03-28 18:58:01 +00:00
{
2010-03-27 16:05:02 +00:00
Rect . Intersect ( C4Rect ( 0 , 0 , Width , Height ) ) ;
2010-03-28 18:58:01 +00:00
if ( ! Rect . Hgt | | ! Rect . Wdt ) return ;
2010-03-27 16:05:02 +00:00
// Multiplicator for changes
const int32_t iMul = fPlus ? + 1 : - 1 ;
// Count pixels
2010-03-28 18:58:01 +00:00
for ( int32_t x = 0 ; x < Rect . Wdt ; x + + )
{
2010-03-27 16:05:02 +00:00
int iHgt = 0 ;
2010-03-28 18:58:01 +00:00
int32_t y ;
for ( y = 1 ; y < Rect . Hgt ; y + + )
{
2010-03-27 16:05:02 +00:00
int32_t iMat = _GetMat ( Rect . x + x , Rect . y + y - 1 ) ;
// Same material? Count it.
2010-03-28 18:58:01 +00:00
if ( iMat = = _GetMat ( Rect . x + x , Rect . y + y ) )
2010-03-27 16:05:02 +00:00
iHgt + + ;
else
2010-03-28 18:58:01 +00:00
{
if ( iMat > = 0 )
2010-03-27 16:05:02 +00:00
{
// Normal material counting
MatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
// Effective material counting enabled?
2010-03-28 18:58:01 +00:00
if ( int32_t iMinHgt = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
// First chunk? Add any material above when checking chunk height
int iAddedHeight = 0 ;
2010-03-28 18:58:01 +00:00
if ( Rect . y & & iHgt + 1 = = y )
2010-03-27 16:05:02 +00:00
iAddedHeight = GetMatHeight ( Rect . x + x , Rect . y - 1 , - 1 , iMat , iMinHgt ) ;
// Check the chunk height
2010-03-28 18:58:01 +00:00
if ( iHgt + 1 + iAddedHeight > = iMinHgt )
{
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight ;
}
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Next chunk of material
iHgt = 0 ;
}
2010-03-28 18:58:01 +00:00
}
2010-03-27 16:05:02 +00:00
// Check last pixel
int32_t iMat = _GetMat ( Rect . x + x , Rect . y + Rect . Hgt - 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iMat > = 0 )
{
2010-03-27 16:05:02 +00:00
// Normal material counting
MatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
// Minimum height counting?
2010-03-28 18:58:01 +00:00
if ( int32_t iMinHgt = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
int iAddedHeight1 = 0 , iAddedHeight2 = 0 ;
// Add any material above for chunk size check
2010-03-28 18:58:01 +00:00
if ( Rect . y & & iHgt + 1 = = Rect . Hgt )
2010-03-27 16:05:02 +00:00
iAddedHeight1 = GetMatHeight ( Rect . x + x , Rect . y - 1 , - 1 , iMat , iMinHgt ) ;
// Add any material below for chunk size check
2010-03-28 18:58:01 +00:00
if ( Rect . y + y < Height )
2010-03-27 16:05:02 +00:00
iAddedHeight2 = GetMatHeight ( Rect . x + x , Rect . y + Rect . Hgt , 1 , iMat , iMinHgt ) ;
// Chunk tall enough?
2010-03-28 18:58:01 +00:00
if ( iHgt + 1 + iAddedHeight1 + iAddedHeight2 > = : : MaterialMap . Map [ iMat ] . MinHeightCount )
{
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * ( iHgt + 1 ) ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight1 < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight1 ;
2010-03-28 18:58:01 +00:00
if ( iAddedHeight2 < iMinHgt )
2010-03-27 16:05:02 +00:00
EffectiveMatCount [ iMat ] + = iMul * iAddedHeight2 ;
}
}
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-06-05 15:20:41 +00:00
C4Landscape Landscape ;