// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////
// INCLUDE //
/////////////
# include "stdpch.h"
// Misc
# include "nel/misc/vectord.h"
# include "nel/misc/path.h"
# include "nel/misc/smart_ptr.h"
# include "nel/misc/progress_callback.h"
# include "nel/misc/async_file_manager.h"
# include "nel/misc/bitmap.h"
# include "nel/misc/polygon.h"
// 3D Interface.
# include "nel/3d/u_landscape.h"
# include "nel/3d/u_scene.h"
# include "nel/3d/u_driver.h"
# include "nel/3d/u_texture.h"
// Georges
# include "nel/georges/u_form.h"
# include "nel/georges/u_form_elm.h"
# include "nel/georges/u_form_loader.h"
// Client
# include "global.h"
# include "continent.h"
# include "light_cycle_manager.h" // \todo GUIGUI : maybe change this when the time will be better managed.
# include "door_manager.h"
# include "client_cfg.h"
# include "ig_client.h"
# include "pacs_client.h"
# include "village.h"
# include "ig_callback.h"
# include "streamable_ig.h"
# include "weather_manager_client.h"
# include "weather.h"
# include "entities.h"
# include "fog_map.h"
# include "demo.h"
# include "ingame_database_manager.h"
# include "sky_render.h"
# include "fix_season_data.h"
# include "ig_season_callback.h"
# include "user_entity.h"
# include "micro_life_manager.h"
# include "zone_util.h"
# include "mesh_camera_col_manager.h"
# include "misc.h"
# include "sheet_manager.h"
# include "continent_manager.h"
# include "connection.h"
# include "water_env_map_rdr.h"
# include "input.h"
# include "bg_downloader_access.h"
// Game Share
# include "game_share/georges_helper.h"
# include "game_share/season_file_ext.h"
// R2 Share
# include "game_share/scenario_entry_points.h"
# include "r2/editor.h"
// std
# include <vector>
# include <string>
# include <memory>
# include <algorithm>
///////////
// USING //
///////////
using namespace NLMISC ;
using namespace NL3D ;
using namespace std ;
using namespace NLGEORGES ;
////////////
// EXTERN //
////////////
extern ULandscape * Landscape ;
extern UScene * Scene ;
extern UScene * SceneRoot ;
extern UInstanceGroup * BackgroundIG ;
extern UDriver * Driver ;
extern UVisualCollisionManager * CollisionManager ;
extern bool InitCloudScape ;
extern bool FirstFrame ;
extern CContinentManager ContinentMngr ;
//-----------------------------------------------
// CUserLandMark
//-----------------------------------------------
NLMISC : : CRGBA CUserLandMark : : getColor ( ) const
{
return _LandMarksColor [ Type ] ;
}
//-----------------------------------------------
// CFogOfWar
//-----------------------------------------------
//===================================================================================
CFogOfWar : : ~ CFogOfWar ( )
{
if ( Tx ! = NULL )
Driver - > deleteTextureMem ( Tx ) ;
}
//===================================================================================
uint8 * CFogOfWar : : getData ( )
{
return ( Tx ! = NULL ) ? Tx - > getPointer ( ) : NULL ;
}
//===================================================================================
sint16 CFogOfWar : : getRealWidth ( )
{
return ( Tx ! = NULL ) ? ( sint16 ) Tx - > getImageWidth ( ) : 0 ;
}
//===================================================================================
sint16 CFogOfWar : : getRealHeight ( )
{
return ( Tx ! = NULL ) ? ( sint16 ) Tx - > getImageHeight ( ) : 0 ;
}
//===================================================================================
bool CFogOfWar : : createData ( sint16 w , sint16 h )
{
if ( Tx ! = NULL )
Driver - > deleteTextureMem ( Tx ) ;
MapWidth = w ;
MapHeight = h ;
uint32 WReal = NLMISC : : raiseToNextPowerOf2 ( MapWidth ) ;
uint32 HReal = NLMISC : : raiseToNextPowerOf2 ( MapHeight ) ;
Tx = Driver - > createTextureMem ( WReal , HReal , CBitmap : : Alpha ) ;
if ( Tx = = NULL )
return false ;
Tx - > setWrapS ( NL3D : : UTexture : : Clamp ) ;
Tx - > setWrapT ( NL3D : : UTexture : : Clamp ) ;
uint8 * pData = Tx - > getPointer ( ) ;
// Set the texture to black (not discovered)
for ( uint32 j = 0 ; j < WReal * HReal ; + + j )
pData [ j ] = 0 ;
// Upload it
Tx - > touch ( ) ;
return true ;
}
//===================================================================================
void CFogOfWar : : explored ( sint16 /* mapPosX */ , sint16 /* mapPosY */ )
{
// TODO trap : do something better than upload the whole texture
if ( Tx ! = NULL )
Tx - > touch ( ) ;
}
//===================================================================================
void CFogOfWar : : load ( const std : : string & /* contName */ )
{
/* // Temporary comment : see this when server ready
string fileName = " save/fow_ " + contName + " _ " + PlayerSelectedFileName + " .ibmp " ;
// Try to load the file corresponding
CIFile inFile ;
if ( inFile . open ( fileName ) )
{
serial ( inFile ) ;
}
else
{
// If the file do not exist create a new texture
// Look in all the maps to know the texture map size and apply a ratio to this size
CWorldSheet * pWS = dynamic_cast < CWorldSheet * > ( SheetMngr . get ( CSheetId ( " ryzom.world " ) ) ) ;
if ( pWS = = NULL ) return ;
for ( uint32 i = 0 ; i < pWS - > Maps . size ( ) ; + + i )
{
SMap & rM = pWS - > Maps [ i ] ;
if ( strncmp ( rM . Name . c_str ( ) , " continent " , 9 ) = = 0 )
{
if ( stricmp ( rM . ContinentName . c_str ( ) , contName . c_str ( ) ) = = 0 )
{
// get the size of the bitmap
uint32 nWidth = 0 , nHeight = 0 ;
string path = CPath : : lookup ( rM . BitmapName , false ) ;
if ( ! path . empty ( ) )
CBitmap : : loadSize ( path , nWidth , nHeight ) ;
// create the texture fow
if ( ( nWidth ! = 0 ) & & ( nHeight ! = 0 ) )
{
MapWidth = ( sint16 ) nWidth / 4 ;
MapHeight = ( sint16 ) nHeight / 4 ;
createData ( MapWidth , MapHeight ) ;
}
MinX = rM . MinX ;
MinY = rM . MinY ;
MaxX = rM . MaxX ;
MaxY = rM . MaxY ;
return ;
}
}
}
}
*/
}
//===================================================================================
void CFogOfWar : : save ( const std : : string & /* contName */ )
{
/* // Temporary comment : see this when server ready
string fileName = " save/fow_ " + contName + " _ " + PlayerSelectedFileName + " .ibmp " ;
// Try to load the file corresponding
COFile inFile ;
if ( inFile . open ( fileName ) )
serial ( inFile ) ;
*/
}
/////////////
// METHODS //
/////////////
//-----------------------------------------------
// CContinent :
// Constructor.
//-----------------------------------------------
CContinent : : CContinent ( )
{
// Newbie = false;
} // CContinent //
class CChangeTaskPriority : public CTaskManager : : IChangeTaskPriority
{
virtual float getTaskPriority ( const IRunnable & runnable )
{
const NLMISC : : IRunnablePos * _3dRunnable = dynamic_cast < const NLMISC : : IRunnablePos * > ( & runnable ) ;
if ( _3dRunnable )
{
return ( _3dRunnable - > Position - UserEntity - > pos ( ) ) . norm ( ) ;
}
return 0 ;
}
} ChangeTaskPriority ;
//===================================================================================
void CContinent : : setup ( )
{
if ( SheetName . empty ( ) )
{
nlwarning ( " SheetName not set : cannot setup continent " ) ;
return ;
}
CEntitySheet * pES = SheetMngr . get ( CSheetId ( SheetName ) ) ;
CContinentSheet * pCS = NULL ;
if ( pES - > type ( ) = = CEntitySheet : : CONTINENT )
pCS = ( CContinentSheet * ) pES ;
if ( pCS = = NULL )
{
nlwarning ( " Bad type for continent form %s. " , SheetName . c_str ( ) ) ;
return ;
}
// copy basics parameters of sheet
CContinentParameters : : operator = ( pCS - > Continent ) ;
// setup weather functions
for ( uint k = 0 ; k < EGSPD : : CSeason : : Invalid ; + + k )
{
WeatherFunction [ k ] . buildFromSheet ( pCS - > WeatherFunction [ k ] , WeatherManager ) ;
}
/*
nlinfo ( " Seasons for continent %s " , SheetName . c_str ( ) ) ;
nlinfo ( " ================================== " ) ;
for ( uint k = 0 ; k < EGSPD : : CSeason : : Invalid ; + + k )
{
nlinfo ( " Season = %s, num setups = %d " , EGSPD : : CSeason : : toString ( ( EGSPD : : CSeason : : TSeason ) k ) . c_str ( ) , ( int ) WeatherFunction [ k ] . getNumWeatherSetups ( ) ) ;
for ( uint l = 0 ; l < WeatherFunction [ k ] . getNumWeatherSetups ( ) ; + + l )
{
if ( WeatherFunction [ k ] . getWeatherSetup ( l ) )
{
nlinfo ( " Setup %d for season %s is %s " , ( int ) l , EGSPD : : CSeason : : toString ( ( EGSPD : : CSeason : : TSeason ) k ) . c_str ( ) , NLMISC : : CStringMapper : : unmap ( WeatherFunction [ k ] . getWeatherSetup ( l ) - > SetupName ) . c_str ( ) ) ;
}
else
{
nlinfo ( " Setup %d not found " , ( int ) l ) ;
}
}
}
*/
uint k ;
// setup villages
for ( k = 0 ; k < pCS - > Villages . size ( ) ; + + k )
{
CVillage * village = new CVillage ;
if ( village - > setupFromSheet ( Scene , pCS - > Villages [ k ] , & IGLoaded ) )
_Villages . add ( village ) ;
else
delete village ;
}
// Setup outpost
_Outposts . clear ( ) ;
for ( k = 0 ; k < pCS - > Continent . ZCList . size ( ) ; + + k )
{
// must add the ruins in 3D?
bool mustAddRuins = pCS - > Continent . ZCList [ k ] . EnableRuins ;
// add a village for ruins display?
CVillage * village = NULL ;
if ( mustAddRuins )
{
village = new CVillage ;
if ( village - > setupOutpost ( Scene , pCS - > Continent . ZCList [ k ] , k , & IGLoaded ) )
_Villages . add ( village ) ;
else
{
delete village ;
village = NULL ;
}
}
// add an outpost
COutpost outpost ;
if ( outpost . setupOutpost ( pCS - > Continent . ZCList [ k ] , k , village ) )
_Outposts . push_back ( outpost ) ;
}
// setup fog of war
FoW . load ( Name ) ;
}
//-----------------------------------------------
class CPCBank : public IProgressCallback
{
virtual void progress ( float /* progressValue */ ) { }
} ;
CPCBank PCBank ;
static uint getNumZones ( )
{
if ( Landscape = = NULL ) return 0 ;
std : : vector < std : : string > zoneLoaded ;
Landscape - > getAllZoneLoaded ( zoneLoaded ) ;
return ( uint ) zoneLoaded . size ( ) ;
}
//-----------------------------------------------
// select :
// Update global parameters like the texture for the micro veget.
//-----------------------------------------------
void CContinent : : select ( const CVectorD & pos , NLMISC : : IProgressCallback & progress , bool complete , bool unhibernate , EGSPD : : CSeason : : TSeason season )
{
pauseBGDownloader ( ) ;
CNiceInputAuto niceInputs ;
// Season has changed ?
Season = season ;
if ( Landscape ) Landscape - > setTileColor ( TileColorMono [ Season ] , TileColorFactor [ Season ] ) ;
// First frame
FirstFrame = true ;
{
H_AUTO ( InitRZWorldLanscapeShow )
// If continent is an indoor, hde the landscape
if ( Landscape )
{
if ( Indoor )
Landscape - > hide ( ) ;
else
Landscape - > show ( ) ;
}
}
bool toto = false ;
if ( complete )
{
// Progress bar
progress . progress ( 0 ) ;
progress . pushCropedValues ( 0 , 1.f / 3.f ) ;
{
H_AUTO ( InitRZWorldIndoor )
if ( ! ClientCfg . Light )
{
if ( Landscape )
{
Landscape - > removeAllZones ( ) ;
toto = true ;
// If continent is an indoor, hde the landscape
if ( ! Indoor )
{
// Change the MicroVeget Texture.
string microVegetSeason = MicroVeget ;
SeasonPostfixTextureFilename ( microVegetSeason , Season ) ;
Landscape - > loadVegetableTexture ( microVegetSeason ) ;
// Change the Material for static and dynamic PointLights
Landscape - > setPointLightDiffuseMaterial ( LandscapePointLightMaterial ) ;
}
}
}
}
// Initialize Landscape IG Callbacks.
{
H_AUTO ( InitRZWorldInitCallbacks )
initLandscapeIGCallbacks ( ) ;
nlassert ( IGCallbacks ) ; // forgot to call ::initLandscapeIGCallbacks()
if ( ! ClientCfg . Light )
{
// Add weather as an observer (to know when an ig is added, and to set its lightmaps color accordingly)
registerObserver ( & LightCycleManager ) ;
IGCallbacks - > registerObserver ( & LightCycleManager ) ;
// register the LightCycleManager as an observer to Objects that may create IGs
IGSeasonCallback . Season = Season ;
registerObserver ( & IGSeasonCallback ) ;
IGCallbacks - > registerObserver ( & IGSeasonCallback ) ;
// register the Camera collision manager
registerObserver ( & MeshCameraColManager ) ;
if ( ! Indoor )
{
// Change LOD texture
try
{
// Get the CoarseMeshMap for this season
string seasonname = CoarseMeshMap ;
SeasonPostfixTextureFilename ( seasonname , Season ) ;
// Set the texture for the coarse mesh manager
Scene - > setCoarseMeshManagerTexture ( CPath : : lookup ( seasonname ) . c_str ( ) ) ;
}
catch ( const Exception & e )
{
nlwarning ( e . what ( ) ) ;
}
}
}
// Register door handling (when an ig is added check all shapes for doors and add to the door manager)
registerObserver ( & IGDoorCallback ) ;
}
{
H_AUTO ( InitRZWorldPacs )
releasePACS ( ) ;
// Init PACS
std : : string pacsRBankPath = CPath : : lookup ( PacsRBank , false ) ;
std : : string pacsGRPath = CPath : : lookup ( PacsGR , false ) ;
if ( ! pacsRBankPath . empty ( ) & & ! pacsGRPath . empty ( ) )
initPACS ( pacsRBankPath . c_str ( ) , pacsGRPath . c_str ( ) , progress ) ;
else
initPACS ( 0 , 0 , progress ) ;
// Set the move container
if ( IGCallbacks ) IGCallbacks - > setMoveContainer ( PACS ) ;
}
{
H_AUTO ( InitRZWorldBuildings )
// No landscape IG in indoors
if ( ! Indoor )
{
if ( ! ClientCfg . Light & & Landscape )
{
// Init ig
try
{
LandscapeIGManager . initIG ( Scene , CPath : : lookup ( LandscapeIG ) . c_str ( ) , Driver , Season , & progress ) ;
}
catch ( const Exception & e )
{
nlwarning ( e . what ( ) ) ;
}
}
// Get IGs for the continent with their name.
vector < pair < UInstanceGroup * , string > > igsWithNames ;
LandscapeIGManager . getAllIGWithNames ( igsWithNames ) ;
// Associate IGs with the ZC number or -1 if there is no ZC.
for ( uint i = 0 ; i < igsWithNames . size ( ) ; + + i )
{
string igZone = toLower ( CFile : : getFilenameWithoutExtension ( igsWithNames [ i ] . second ) ) ;
// Search for the IG name in the ZC list to associate.
for ( uint j = 0 ; j < ZCList . size ( ) ; + + j )
{
// Get the outpost ZC
COutpost * outpost = getOutpost ( j ) ;
if ( outpost )
{
// If name matching -> this zone should be a ZC.
string outpostZone = toLower ( CFile : : getFilenameWithoutExtension ( ZCList [ j ] . Name ) ) ;
if ( igZone = = outpostZone )
{
nlctassert ( RZ_MAX_BUILDING_PER_OUTPOST = = 4 ) ;
// Check there is all information in the IG for a ZC and initialize.
bool zcOK [ RZ_MAX_BUILDING_PER_OUTPOST + 1 ] = { false , false , false , false , false } ;
UInstanceGroup * ig = igsWithNames [ i ] . first ;
uint k ;
for ( k = 0 ; k < ig - > getNumInstance ( ) ; + + k )
{
if ( ig - > getInstanceName ( k ) = = " flag_zc " )
{
// todo hulud handle outpost flag
zcOK [ 0 ] = true ;
}
// For each building
uint b ;
for ( b = 0 ; b < RZ_MAX_BUILDING_PER_OUTPOST ; b + + )
{
// Good one ?
if ( ig - > getInstanceName ( k ) = = ( " bat_zc_0 " + toString ( b + 1 ) ) )
{
// Set the position
CVector pos = ig - > getInstancePos ( k ) ;
CQuat rot = ig - > getInstanceRot ( k ) ;
outpost - > setBuildingPosition ( b , rot , pos ) ;
zcOK [ b + 1 ] = true ;
}
}
}
// There are not enough information in the IG for ZC.
for ( k = 0 ; k < RZ_MAX_BUILDING_PER_OUTPOST + 1 ; k + + )
if ( ! zcOK [ k ] )
break ;
// Failed ?
if ( k ! = RZ_MAX_BUILDING_PER_OUTPOST + 1 )
nlwarning ( " CContinent::select : Zone '%s' should be a ZC but some doomy are missing. " , igsWithNames [ i ] . second . c_str ( ) ) ;
// Outpost found, and setuped. stop
break ;
}
}
}
// Add IGs with the Num ZC associated in the callback system.
if ( IGCallbacks ) IGCallbacks - > addIG ( igsWithNames [ i ] . first ) ;
}
// Register outpost collisions and Display
initOutpost ( ) ;
}
}
if ( ! ClientCfg . Light )
{
// Progress bar
progress . popCropedValues ( ) ;
progress . progress ( 1.f / 3.f ) ;
progress . pushCropedValues ( 1.f / 3.f , 2.f / 3.f ) ;
{
H_AUTO ( InitRZWorldTileBank )
// Select the tile bank
if ( Landscape )
{
if ( ! Indoor )
{
string farBankSeason = FarBank ;
SeasonPostfixTextureFilename ( farBankSeason , Season ) ;
if ( ! SmallBank . empty ( ) & & ! farBankSeason . empty ( ) )
{
std : : string smallBankPath = CPath : : lookup ( SmallBank , false ) ;
std : : string farBankSeasonPath = CPath : : lookup ( farBankSeason , false ) ;
if ( ! smallBankPath . empty ( ) & & ! farBankSeasonPath . empty ( ) )
{
Landscape - > loadBankFiles ( smallBankPath , farBankSeasonPath ) ;
}
// Postfix tiles and vegetset by the season string
Landscape - > postfixTileFilename ( CSeasonFileExt : : getExtension ( Season ) ) ;
Landscape - > postfixTileVegetableDesc ( CSeasonFileExt : : getExtension ( Season ) ) ;
// Flush the tiles
Landscape - > flushTiles ( progress ) ;
}
}
}
}
// Not an indoor ?
if ( ! Indoor )
{
{
H_AUTO ( InitRZWorldSky )
// load the sky if any
initSky ( ) ;
// build the canopee
try
{
nlassert ( CurrSeason < EGSPD : : CSeason : : Invalid ) ;
if ( ! CanopyIGfileName [ CurrSeason ] . empty ( ) & & CurrSeason ! = EGSPD : : CSeason : : Invalid )
{
BackgroundIG = UInstanceGroup : : createInstanceGroup ( CanopyIGfileName [ CurrSeason ] ) ;
}
else
{
BackgroundIG = UInstanceGroup : : createInstanceGroup ( BackgroundIGName ) ;
}
}
catch ( const Exception & e )
{
nlwarning ( e . what ( ) ) ;
}
if ( BackgroundIG )
{
if ( SceneRoot )
{
// Add the IG to the scene
BackgroundIG - > addToScene ( * SceneRoot , Driver ) ;
// See for which objects distance should be overriden (object which use a .PLANT sheet)
uint numInstances = BackgroundIG - > getNumInstance ( ) ;
uint k ;
for ( k = 0 ; k < numInstances ; + + k )
{
// Select the texture function of the season
UInstance instance = BackgroundIG - > getInstance ( k ) ;
if ( ! instance . empty ( ) )
{
instance . selectTextureSet ( Season ) ;
}
}
}
}
}
}
}
// Progress bar
progress . popCropedValues ( ) ;
progress . progress ( 2.f / 3.f ) ;
progress . pushCropedValues ( 2.f / 3.f , 1 ) ;
} // complete
if ( complete | | unhibernate )
{
H_AUTO ( InitRZWorldLightCycleManager )
// Touch light setup
LightCycleManager . touch ( ) ;
}
if ( complete )
{
H_AUTO ( InitRZWorldWaterMap )
// init water map
initWaterMap ( ) ;
}
const R2 : : CScenarioEntryPoints : : CCompleteIsland * completeIsland = NULL ;
{
progress . pushCropedValues ( 0 , 3.f / 4.f ) ;
if ( ! ClientCfg . Light )
{
if ( ! Indoor )
{
if ( Landscape )
{
H_AUTO ( InitRZWorldLandscapeIGManager )
// If any zone already loaded into the landscape, must load them to the IGManager.
// Yoyo: this is important for teleportation near a current position, since not so many landscape zones
// will be removed/added.
// Hence, a solution is to reload all igs.
vector < string > zonesLoaded ;
Landscape - > getAllZoneLoaded ( zonesLoaded ) ;
// and try to load the ones which fit the IGManager
vector < NL3D : : UInstanceGroup * > igAdded ;
LandscapeIGManager . loadArrayZoneIG ( zonesLoaded , & igAdded ) ;
// Refresh zone to load/remove.
vector < string > zonesAdded ;
vector < string > zonesRemoved ;
completeIsland = R2 : : CScenarioEntryPoints : : getInstance ( ) . getCompleteIslandFromCoords ( CVector2f ( ( float ) UserEntity - > pos ( ) . x , ( float ) UserEntity - > pos ( ) . y ) ) ;
Landscape - > refreshAllZonesAround ( pos , ClientCfg . Vision + ExtraZoneLoadingVision , zonesAdded , zonesRemoved , progress , completeIsland ? & ( completeIsland - > ZoneIDs ) : NULL ) ;
LandscapeIGManager . unloadArrayZoneIG ( zonesRemoved ) ;
LandscapeIGManager . loadArrayZoneIG ( zonesAdded , & igAdded ) ;
}
}
}
progress . popCropedValues ( ) ;
progress . progress ( 3.f / 4.f ) ;
progress . pushCropedValues ( 3.f / 4.f , 1 ) ;
// Refresh PACS
if ( GR )
{
H_AUTO ( InitRZWorldRefreshPacs )
GR - > refreshLrAroundNow ( pos , LRRefeshRadius ) ;
}
// Refresh streamable object (villages ..)
if ( ! ClientCfg . Light )
{
if ( ClientCfg . VillagesEnabled )
{
H_AUTO ( InitRZWorldForceUpdateStreamable )
forceUpdateStreamable ( pos , progress ) ;
}
}
progress . popCropedValues ( ) ;
}
// Execute only when you change the targeted continent is not the current one.
if ( complete | | unhibernate )
{
// Continent changed -> update entities.
EntitiesMngr . changeContinent ( ) ;
R2 : : getEditor ( ) . onContinentChanged ( ) ;
// Ask to reinit cloudscape
InitCloudScape = true ;
// Set the entity sun contribution parameters
CollisionManager - > setSunContributionPower ( EntitySunContributionPower , EntitySunContributionMaxThreshold ) ;
}
if ( complete )
{
reloadFogMap ( ) ;
// temp for debug : create visualisation of current pacs primitives
// createInstancesFromMoveContainer(Scene, IGCallbacks->getMoveContainer(), NULL);
//
// Progress bar
progress . popCropedValues ( ) ;
}
if ( complete | | unhibernate )
{
if ( ! ClientCfg . Light & & ClientCfg . LandscapeEnabled & & ClientCfg . MicroLifeEnabled )
{
H_AUTO ( InitRZWorldLoadMicroLife )
loadMicroLife ( ) ;
}
}
// Register callback on streaming
CAsyncFileManager : : getInstance ( ) . registerTaskPriorityCallback ( & ChangeTaskPriority ) ;
} // select //
//=========================================================================
void CContinent : : reloadFogMap ( )
{
const R2 : : CScenarioEntryPoints : : CCompleteIsland * completeIsland = R2 : : CScenarioEntryPoints : : getInstance ( ) . getCompleteIslandFromCoords ( CVector2f ( ( float ) UserEntity - > pos ( ) . x , ( float ) UserEntity - > pos ( ) . y ) ) ;
if ( completeIsland )
{
std : : string islandName = toLower ( completeIsland - > Island ) ;
std : : string : : size_type lastPos = islandName . find_last_of ( " _ " ) ;
if ( lastPos ! = std : : string : : npos )
{
islandName = islandName . substr ( lastPos + 1 ) ;
}
// special fogmaps are use for islands
CFogMapBuild fmb ;
enum TMapType { Day = 0 , Night , Dusk , Distance , Depth , NoPrecipitation , NumMap } ;
fmb . Map [ CFogMapBuild : : Day ] = " fog_ " + islandName + " _day.tga " ;
fmb . Map [ CFogMapBuild : : Night ] = " fog_ " + islandName + " _night.tga " ;
fmb . Map [ CFogMapBuild : : Dusk ] = " fog_ " + islandName + " _day.tga " ;
fmb . Map [ CFogMapBuild : : Distance ] = " fog_ " + islandName + " _dist.tga " ;
fmb . Map [ CFogMapBuild : : Depth ] = " fog_ " + islandName + " _depth.tga " ;
fmb . Map [ CFogMapBuild : : NoPrecipitation ] = islandName + " _no_rain.tga " ;
// there is an outtline of 50%, take it in account
float deltaX = 0.25f * ( completeIsland - > XMax - completeIsland - > XMin ) ;
float deltaY = 0.25f * ( completeIsland - > XMax - completeIsland - > XMin ) ;
FogMap . init ( fmb ,
CVector ( ( float ) completeIsland - > XMin + deltaX , ( float ) completeIsland - > YMin + deltaY , 0.f ) ,
CVector ( ( float ) completeIsland - > XMax - deltaX , ( float ) completeIsland - > YMax - deltaY , 0.f )
) ;
bool found = false ;
for ( uint k = 0 ; k < CFogMapBuild : : NumMap & & ! found ; + + k )
{
if ( FogMap . getMap ( ( CFogMap : : TMapType ) k ) . getWidth ( ) ! = 0 ) found = true ;
}
// as a fallback, assume that new fog maps have not been installed, so fallback on the old ones ...
if ( ! found )
{
FogMap . init ( FogMapBuild ) ;
}
}
else
{
FogMap . init ( FogMapBuild ) ;
}
# ifdef NL_DEBUG
nlinfo ( " fog map : (minX, minY) = (%.1f, %.1f), (maxX, maxY) = (%.1f, %.1f) " , FogMap . getMinCoord ( ) . x , FogMap . getMinCoord ( ) . y , FogMap . getMaxCoord ( ) . x , FogMap . getMaxCoord ( ) . y ) ;
# endif
}
//=========================================================================
bool CContinent : : getCorners ( NLMISC : : CVector2f & cornerMin , NLMISC : : CVector2f & cornerMax ) const
{
if ( ! getPosFromZoneName ( ZoneMin , cornerMin ) )
{
nlwarning ( " Can't retrieve continent min corner " ) ;
return false ;
}
if ( ! getPosFromZoneName ( ZoneMax , cornerMax ) )
{
nlwarning ( " Can't retrieve continent max corner " ) ;
return false ;
}
if ( cornerMin . x > cornerMax . x ) std : : swap ( cornerMin . x , cornerMax . x ) ;
if ( cornerMin . y > cornerMax . y ) std : : swap ( cornerMin . y , cornerMax . y ) ;
cornerMax . x + = 160.f ;
cornerMax . y + = 160.f ;
return true ;
}
//=========================================================================
void CContinent : : initWaterMap ( )
{
NLMISC : : CVector2f cornerMin , cornerMax ;
if ( ! getCorners ( cornerMin , cornerMax ) ) return ;
WaterMap . init ( cornerMin , cornerMax ) ;
}
//=========================================================================
void CContinent : : loadMicroLife ( )
{
CMicroLifeManager : : getInstance ( ) . release ( ) ;
NLMISC : : CVector2f cornerMin , cornerMax ;
if ( ! getCorners ( cornerMin , cornerMax ) ) return ;
CMicroLifeManager : : getInstance ( ) . init ( cornerMin , cornerMax ) ;
// register all micro life primitives
CMicroLifeManager : : getInstance ( ) . build ( MicroLifeZones ) ;
}
//=========================================================================
bool CContinent : : isLoadingforced ( const NLMISC : : CVector & pos ) const
{
return _Villages . needCompleteLoading ( pos ) ;
}
//=========================================================================
void CContinent : : updateStreamable ( const NLMISC : : CVector & pos )
{
_Villages . update ( pos ) ;
}
//=========================================================================
void CContinent : : forceUpdateStreamable ( const NLMISC : : CVector & playerPos , NLMISC : : IProgressCallback & progress )
{
_Villages . forceUpdate ( playerPos , progress ) ;
}
//=========================================================================
void CContinent : : removeVillages ( )
{
_Villages . removeAll ( ) ;
}
//=========================================================================
void CContinent : : unselect ( )
{
// remove envmap
if ( SceneRoot & & ! WaterEnvMapCanopyCam . empty ( ) )
{
SceneRoot - > deleteCamera ( WaterEnvMapCanopyCam ) ;
}
WaterEnvMapCanopyCam . detach ( ) ;
if ( CurrentSky . getScene ( ) & & ! WaterEnvMapSkyCam . empty ( ) )
{
CurrentSky . getScene ( ) - > deleteCamera ( WaterEnvMapSkyCam ) ;
}
WaterEnvMapSkyCam . detach ( ) ;
//
if ( ! Indoor )
{
releaseSky ( ) ;
// Setup the Root scene.
if ( BackgroundIG )
{
BackgroundIG - > removeFromScene ( * SceneRoot ) ;
SceneRoot - > deleteInstanceGroup ( BackgroundIG ) ;
BackgroundIG = NULL ;
}
}
// Remove outpost (collisions etc...)
removeOutpost ( ) ;
// Unregister callback on streaming
CAsyncFileManager : : getInstance ( ) . registerTaskPriorityCallback ( NULL ) ;
// Remove the primitive for all entitites (new PACS coming soon and need new primitives).
EntitiesMngr . removeCollision ( ) ;
// Remove the instances (shapes).
EntitiesMngr . removeInstances ( ) ;
// release collision primitives
if ( IGCallbacks )
{
IGCallbacks - > resetContainer ( ) ;
}
// Unload villages
_Villages . forceUnload ( ) ;
// Release PACS
releasePACS ( ) ;
// Initialize Landscape IG Callbacks.
releaseLandscapeIGCallbacks ( ) ;
// Release the IG manager only if where are not in indoor
if ( ! Indoor )
{
// Release the IG manager
if ( Landscape ) LandscapeIGManager . reset ( ) ;
}
// release fog maps
FogMap . release ( ) ;
// Remove weather as an observer
removeObserver ( & LightCycleManager ) ;
// Remove season observer
removeObserver ( & IGSeasonCallback ) ;
// Remove Camera collision observer
removeObserver ( & MeshCameraColManager ) ;
// Remove door management observers
removeObserver ( & IGDoorCallback ) ;
// Release water map
WaterMap . release ( ) ;
// Release water envmap
# ifdef USE_WATER_ENV_MAP
Driver - > deleteWaterEnvMap ( WaterEnvMap ) ;
WaterEnvMap = NULL ;
# endif
}
//=========================================================================
/** Override current fog by the fog in the weather system. This is used when there is bad weather or precipitations
* \ param dest the fog state to modify
* \ param fogIndex the fog to modify ( 0 for main , 1 for canopy )
*/
static void overrideFog ( CFogState & dest , TFogType fogType , float dayNight , float duskRatio , CLightCycleManager : : TLightState lightState , bool /* overrideDist */ , bool overideByWeatherFogDist = true )
{
nlassert ( fogType < NumFogType ) ; // For now, 2 kinds of fogs : main & canopy
if ( ! dest . FogEnabled ) return ;
const CWeatherState & ws = WeatherManager . getCurrWeatherState ( ) ;
if ( ws . FogRatio = = 0.f ) return ; // no need to override fog
// override the fog by the fog indicated in the WeatherManager
NLMISC : : CRGBA fogColor ;
// if there's a new style sky with a fog bitmap *(giving fog depending on hour & weather, use it)
if ( ContinentMngr . cur ( ) & & ContinentMngr . cur ( ) - > CurrentSky . getScene ( ) ! = NULL & & ContinentMngr . cur ( ) - > CurrentSky . hasFogColor ( ) )
{
fogColor = ContinentMngr . cur ( ) - > CurrentSky . computeFogColor ( CClientDate ( RT . getRyzomDay ( ) , ( float ) DayNightCycleHour ) , WeatherManager . getWeatherValue ( ) ) ;
}
else
{
switch ( lightState )
{
case CLightCycleManager : : DayToNight :
{
if ( dayNight < duskRatio )
{
float blendFactor = duskRatio ! = 0 ? dayNight / duskRatio : 0.f ;
fogColor . blendFromui ( ws . FogColorDay , ws . FogColorDusk , ( uint ) ( blendFactor * 256.f ) ) ;
}
else
{
float blendFactor = duskRatio ! = 1 ? ( dayNight - duskRatio ) / ( 1.f - duskRatio ) : 0.f ;
fogColor . blendFromui ( ws . FogColorDusk , ws . FogColorNight , ( uint ) ( blendFactor * 256.f ) ) ;
}
}
break ;
default : // no dusk transition
fogColor . blendFromui ( ws . FogColorDay , ws . FogColorNight , ( uint ) ( dayNight * 256.f ) ) ;
break ;
}
}
float finalFogAlpha = ( float ) dest . FogColor . A * 256.f / 255.f ;
dest . FogColor . blendFromui ( dest . FogColor , fogColor , ( uint ) ( ( 256.f - finalFogAlpha ) * ws . FogRatio ) ) ;
if ( overideByWeatherFogDist )
{
dest . FogEndDist = std : : min ( ws . FogFar [ fogType ] , dest . FogEndDist ) ;
dest . FogStartDist = std : : min ( ws . FogNear [ fogType ] , dest . FogStartDist ) ;
}
}
//=========================================================================
/** Adapt fog dist to the viewport
*/
static inline void makeRangedFog ( CFogState & result , UScene & scene )
{
if ( result . FogEndDist ! = 0.f )
{
float farPlaneDist = scene . getCam ( ) . getFrustum ( ) . Far ;
float newEndFogDist = std : : min ( result . FogEndDist , farPlaneDist ) ;
result . FogStartDist = result . FogStartDist * newEndFogDist / result . FogEndDist ;
result . FogEndDist = newEndFogDist ;
result . FogEnabled = true ;
}
else
{
result . FogEnabled = false ;
}
}
//=========================================================================
void CContinent : : getFogState ( TFogType fogType , float dayNight , float duskRatio , CLightCycleManager : : TLightState lightState , const NLMISC : : CVectorD & pos , CFogState & result , bool overideByWeatherFogDist /*= true*/ )
{
if ( FogStart = = FogEnd )
{
result . FogEnabled = false ;
return ;
}
switch ( fogType )
{
case MainFog : FogMap . getFogParams ( FogStart , FogEnd , ( float ) pos . x , ( float ) pos . y , dayNight , duskRatio , lightState , result ) ; break ;
case CanopyFog : FogMap . getFogParams ( RootFogStart , RootFogEnd , ( float ) pos . x , ( float ) pos . y , dayNight , duskRatio , lightState , result ) ; break ;
default :
nlstop ;
break ;
}
// Override fog because of weather.
overrideFog ( result , fogType , dayNight , duskRatio , lightState , overideByWeatherFogDist ) ;
// normalize fog dist to view frustum
/*
switch ( fogType )
{
case MainFog : if ( Scene ) makeRangedFog ( result , * Scene ) ; break ;
case CanopyFog : if ( SceneRoot ) makeRangedFog ( result , * SceneRoot ) ; break ;
}
*/
/*
if ( fogType = = MainFog )
{
result . FogStartDist * = ( ClientCfg . Vision / ClientCfg . Vision_max ) ;
result . FogEndDist * = ( ClientCfg . Vision / ClientCfg . Vision_max ) ;
}
*/
}
//=========================================================================
bool CContinent : : enumIGs ( IIGEnum * callback )
{
uint numEntities = _Villages . getNumEntities ( ) ;
bool continueEnum = true ;
for ( uint k = 0 ; k < numEntities & & continueEnum ; + + k )
{
CVillage * v = dynamic_cast < CVillage * > ( _Villages . getEntity ( k ) ) ;
if ( v ) // well this should always be the case, but it may change in the future
{
continueEnum = v - > enumIGs ( callback ) ;
}
}
return continueEnum ;
}
//=========================================================================
void CContinent : : registerObserver ( IIGObserver * obs )
{
uint numEntities = _Villages . getNumEntities ( ) ;
for ( uint k = 0 ; k < numEntities ; + + k )
{
CVillage * v = dynamic_cast < CVillage * > ( _Villages . getEntity ( k ) ) ;
if ( v ) // well this should always be the case, but it may change in the future
{
v - > registerObserver ( obs ) ;
}
}
}
//=========================================================================
void CContinent : : removeObserver ( IIGObserver * obs )
{
uint numEntities = _Villages . getNumEntities ( ) ;
for ( uint k = 0 ; k < numEntities ; + + k )
{
CVillage * v = dynamic_cast < CVillage * > ( _Villages . getEntity ( k ) ) ;
if ( v ) // well this should always be the case, but it may change in the future
{
v - > removeObserver ( obs ) ;
}
}
}
//=========================================================================
bool CContinent : : isObserver ( IIGObserver * obs ) const
{
uint numEntities = _Villages . getNumEntities ( ) ;
for ( uint k = 0 ; k < numEntities ; + + k )
{
CVillage * v = dynamic_cast < CVillage * > ( _Villages . getEntity ( k ) ) ;
if ( v ) // well this should always be the case, but it may change in the future
{
if ( v - > isObserver ( obs ) )
return true ;
}
}
return false ;
}
//=========================================================================
COutpost * CContinent : : getOutpost ( uint outpostId )
{
for ( uint i = 0 ; i < _Outposts . size ( ) ; i + + )
{
// Outpost ?
if ( _Outposts [ i ] . getOutpostId ( ) = = ( sint ) outpostId )
return & _Outposts [ i ] ;
}
return NULL ;
}
//=========================================================================
void CContinent : : initOutpost ( )
{
for ( uint i = 0 ; i < _Outposts . size ( ) ; i + + )
{
_Outposts [ i ] . initOutpost ( ) ;
}
}
//=========================================================================
void CContinent : : removeOutpost ( )
{
for ( uint i = 0 ; i < _Outposts . size ( ) ; i + + )
{
_Outposts [ i ] . removeOutpost ( ) ;
}
}
//=========================================================================
void CContinent : : dumpVillagesLoadingZones ( const std : : string & filename )
{
const uint NUM_METER_PER_PIX = 4 ;
CBitmap outBitmap ;
CVector2f minPos , maxPos ;
getPosFromZoneName ( ZoneMin , minPos ) ;
getPosFromZoneName ( ZoneMax , maxPos ) ;
if ( minPos . x > maxPos . x ) std : : swap ( minPos . x , maxPos . x ) ;
if ( minPos . y > maxPos . y ) std : : swap ( minPos . y , maxPos . y ) ;
uint width = ( uint ) ( ( maxPos . x - minPos . x ) / NUM_METER_PER_PIX ) ;
uint height = ( uint ) ( ( maxPos . y - minPos . y ) / NUM_METER_PER_PIX ) ;
outBitmap . resize ( width , height ) ;
for ( uint k = 0 ; k < _Villages . getNumEntities ( ) ; + + k )
{
CVillage & v = * safe_cast < CVillage * > ( _Villages . getEntity ( k ) ) ;
if ( ! v . isOutpost ( ) )
{
const CStreamableIG & sig = v . getIG ( ) ;
drawDisc ( outBitmap , ( sig . getPos ( ) . x - minPos . x ) / NUM_METER_PER_PIX , ( sig . getPos ( ) . y - minPos . y ) / NUM_METER_PER_PIX , sig . getUnloadRadius ( ) / NUM_METER_PER_PIX , CRGBA ( 0 , 0 , 100 ) , true ) ;
drawDisc ( outBitmap , ( sig . getPos ( ) . x - minPos . x ) / NUM_METER_PER_PIX , ( sig . getPos ( ) . y - minPos . y ) / NUM_METER_PER_PIX , sig . getLoadRadius ( ) / NUM_METER_PER_PIX , CRGBA ( 0 , 100 , 0 ) , true ) ;
drawDisc ( outBitmap , ( sig . getPos ( ) . x - minPos . x ) / NUM_METER_PER_PIX , ( sig . getPos ( ) . y - minPos . y ) / NUM_METER_PER_PIX , sig . getForceLoadRadius ( ) / NUM_METER_PER_PIX , CRGBA ( 100 , 0 , 0 ) , true ) ;
}
}
// load the map and do a lerp between the 2 bitmaps
if ( ! WorldMap . empty ( ) )
{
std : : string path = CPath : : lookup ( WorldMap , false ) ;
if ( ! path . empty ( ) )
{
CIFile stream ;
if ( stream . open ( path ) )
{
CBitmap worldMap ;
if ( worldMap . load ( stream ) )
{
worldMap . convertToType ( CBitmap : : RGBA ) ;
worldMap . flipV ( ) ;
worldMap . resample ( outBitmap . getWidth ( ) , outBitmap . getHeight ( ) ) ;
outBitmap . blend ( outBitmap , worldMap , 127 , true ) ;
}
}
}
}
drawDisc ( outBitmap , ( ( float ) UserEntity - > pos ( ) . x - minPos . x ) / ( float ) NUM_METER_PER_PIX , ( ( float ) UserEntity - > pos ( ) . y - minPos . y ) / ( float ) NUM_METER_PER_PIX , 2 , CRGBA : : Magenta ) ;
// draw grid
const uint subdiv = 500 ;
const CRGBA lineCol ( CRGBA : : Yellow ) ;
sint minY = ( sint ) floor ( minPos . y / subdiv ) ;
sint maxY = ( sint ) ceil ( maxPos . y / subdiv ) ;
sint minX = ( sint ) floor ( minPos . x / subdiv ) ;
sint maxX = ( sint ) ceil ( maxPos . x / subdiv ) ;
// draw HLines
for ( sint y = minY ; y < maxY ; y + + )
{
sint ypix = ( sint ) ( ( y * subdiv - minPos . y ) / NUM_METER_PER_PIX ) ;
if ( ypix > = 0 & & ypix < ( sint ) height )
{
for ( uint x = 0 ; x < width ; x + + )
{
CRGBA * pCol = ( CRGBA * ) ( & outBitmap . getPixels ( ) [ 0 ] ) ;
pCol [ ypix * width + x ] = lineCol ;
}
}
}
// draw VLines
for ( sint x = minX ; x < maxX ; x + + )
{
sint xpix = ( sint ) ( ( x * subdiv - minPos . x ) / NUM_METER_PER_PIX ) ;
if ( xpix > = 0 & & xpix < ( sint ) width )
{
for ( uint y = 0 ; y < height ; y + + )
{
CRGBA * pCol = ( CRGBA * ) ( & outBitmap . getPixels ( ) [ 0 ] ) ;
pCol [ y * width + xpix ] = lineCol ;
}
}
}
COFile outFile ;
if ( outFile . open ( filename ) )
{
try
{
outBitmap . writeTGA ( outFile , 24 , true ) ;
}
catch ( const EStream & )
{
}
}
}
//=========================================================================
void CContinent : : dumpFogMap ( CFogMapBuild : : TMapType mapType , const std : : string & filename , TChannel channel /*= ChannelRGBA*/ , const CRGBA channelLookup [ 256 ] /* = NULL */ )
{
CBitmap outBitmap = FogMap . getMap ( mapType ) ;
outBitmap . convertToType ( CBitmap : : RGBA ) ;
if ( channel ! = ChannelRGBA )
{
CRGBA * pix = ( CRGBA * ) & outBitmap . getPixels ( 0 ) [ 0 ] ;
const CRGBA * endPix = pix + outBitmap . getWidth ( ) * outBitmap . getHeight ( ) ;
while ( pix ! = endPix )
{
uint8 intensity = ( ( uint8 * ) pix ) [ channel ] ;
if ( ! channelLookup )
{
* pix = CRGBA ( intensity , intensity , intensity , intensity ) ;
}
else
{
* pix = channelLookup [ intensity ] ;
}
+ + pix ;
}
}
if ( outBitmap . getWidth ( ) = = 0 | | outBitmap . getHeight ( ) = = 0 ) return ;
CVector pos = MainCam . getMatrix ( ) . getPos ( ) ;
float mx , my ;
FogMap . worldPosToMapPos ( pos . x , pos . y , mx , my ) ;
// load the map and do a lerp between the 2 bitmaps
if ( ! WorldMap . empty ( ) )
{
std : : string path = CPath : : lookup ( WorldMap , false ) ;
if ( ! path . empty ( ) )
{
CIFile stream ;
if ( stream . open ( path ) )
{
CBitmap worldMap ;
if ( worldMap . load ( stream ) )
{
worldMap . convertToType ( CBitmap : : RGBA ) ;
worldMap . resample ( outBitmap . getWidth ( ) , outBitmap . getHeight ( ) ) ;
outBitmap . blend ( outBitmap , worldMap , 127 , true ) ;
}
}
}
}
drawDisc ( outBitmap , mx * outBitmap . getWidth ( ) , my * outBitmap . getHeight ( ) , 2.f , CRGBA : : Magenta ) ;
COFile outFile ;
if ( outFile . open ( filename ) )
{
try
{
outBitmap . writeTGA ( outFile , 24 ) ;
}
catch ( const EStream & )
{
}
}
}
//=========================================================================
void CContinent : : initSky ( )
{
if ( ! SkySheet [ CurrSeason ] . empty ( ) )
{
// get the sky sheet
CEntitySheet * skySheet = SheetMngr . get ( NLMISC : : CSheetId ( SkySheet [ CurrSeason ] ) ) ;
if ( skySheet & & skySheet - > Type = = CEntitySheet : : SKY )
{
// new-style sky
CurrentSky . init ( Driver , * static_cast < CSkySheet * > ( skySheet ) , false , WorldLightCycle . NumHours ) ;
}
# ifdef USE_WATER_ENV_MAP
WaterEnvMapRdr . Sky = & CurrentSky ;
# endif
}
else
{
createSkyScene ( ) ;
// fallback to previous sky version
Sky = SkyScene - > createInstance ( SkyDay ) ;
Sky2ndPass = SkyScene - > createInstance ( SkyDay ) ; // Sky shape used for second pass. We use it to keep pointers on textures
SkyFogPart = SkyScene - > createInstance ( SkyFogPartName ) ;
// Setup the 2nd
if ( ! Sky . empty ( ) )
{
DaySkySetup . buildFromInstance ( Sky , 0 ) ; // day textures are at stage 0
NightSkySetup . buildFromInstance ( Sky , 1 ) ; // night textures are at stage 1
}
}
}
//=========================================================================
void CContinent : : releaseSky ( )
{
// Remove the (old-style) sky
if ( ! Sky . empty ( ) )
{
SkyScene - > deleteInstance ( Sky ) ;
SkyScene - > deleteInstance ( Sky2ndPass ) ;
SkyScene - > deleteInstance ( SkyFogPart ) ;
Sky = NULL ;
Sky2ndPass = NULL ;
SkyFogPart = NULL ;
}
deleteSkyScene ( ) ;
// Release the (new-style) sky
CurrentSky . release ( ) ;
}