mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-22 17:08:43 +00:00
1633 lines
48 KiB
C++
1633 lines
48 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 "std3d.h"
|
|
|
|
#include "nel/3d/scene.h"
|
|
#include "nel/3d/trav_scene.h"
|
|
#include "nel/3d/hrc_trav.h"
|
|
#include "nel/3d/clip_trav.h"
|
|
#include "nel/3d/light_trav.h"
|
|
#include "nel/3d/anim_detail_trav.h"
|
|
#include "nel/3d/load_balancing_trav.h"
|
|
#include "nel/3d/render_trav.h"
|
|
#include "nel/3d/transform.h"
|
|
#include "nel/3d/camera.h"
|
|
#include "nel/3d/landscape_model.h"
|
|
#include "nel/3d/driver.h"
|
|
#include "nel/3d/transform_shape.h"
|
|
#include "nel/3d/mesh_base.h"
|
|
#include "nel/3d/mesh_base_instance.h"
|
|
#include "nel/3d/mesh_instance.h"
|
|
#include "nel/3d/mesh_mrm_instance.h"
|
|
#include "nel/3d/mesh_mrm_skinned_instance.h"
|
|
#include "nel/3d/mesh_multi_lod_instance.h"
|
|
#include "nel/3d/shape_bank.h"
|
|
#include "nel/3d/skeleton_model.h"
|
|
#include "nel/3d/particle_system_model.h"
|
|
#include "nel/3d/coarse_mesh_manager.h"
|
|
#include "nel/3d/cluster.h"
|
|
#include "nel/3d/scene_group.h"
|
|
#include "nel/3d/flare_model.h"
|
|
#include "nel/3d/water_model.h"
|
|
#include "nel/3d/vegetable_blend_layer_model.h"
|
|
#include "nel/3d/root_model.h"
|
|
#include "nel/3d/point_light_model.h"
|
|
#include "nel/3d/animation.h"
|
|
#include "nel/3d/lod_character_manager.h"
|
|
#include "nel/3d/seg_remanence.h"
|
|
#include "nel/3d/async_texture_manager.h"
|
|
#include "nel/3d/water_env_map.h"
|
|
#include "nel/3d/skeleton_spawn_script.h"
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include "nel/misc/time_nl.h"
|
|
#include "nel/misc/file.h"
|
|
#include "nel/misc/path.h"
|
|
|
|
//
|
|
#include "nel/misc/system_info.h"
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
|
|
#define NL3D_SCENE_COARSE_MANAGER_TEXTURE "nel_coarse_texture.tga"
|
|
|
|
|
|
// The manager is limited to a square of 3000m*3000m around the camera. Beyond, models are clipped individually (bad!!).
|
|
const float NL3D_QuadGridClipManagerRadiusMax= 1500;
|
|
const float NL3D_QuadGridClipClusterSize= 400;
|
|
const uint NL3D_QuadGridClipNumDist= 10;
|
|
const float NL3D_QuadGridClipMaxDist= 1000;
|
|
|
|
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_SIZE 64
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_BLUR_SIZE 2
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_START 40
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_END 50
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_IN_SCREEN 16
|
|
#define NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_AROUND 64
|
|
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
|
|
void CScene::registerBasics()
|
|
{
|
|
CTransform::registerBasic();
|
|
CCamera::registerBasic();
|
|
CMeshBaseInstance::registerBasic();
|
|
CMeshInstance::registerBasic();
|
|
CMeshMRMInstance::registerBasic();
|
|
CMeshMRMSkinnedInstance::registerBasic();
|
|
CLandscapeModel::registerBasic();
|
|
CTransformShape::registerBasic();
|
|
CSkeletonModel::registerBasic();
|
|
CParticleSystemModel::registerBasic() ;
|
|
CMeshMultiLodInstance::registerBasic();
|
|
CCluster::registerBasic();
|
|
CFlareModel::registerBasic();
|
|
CWaterModel::registerBasic();
|
|
CWaveMakerModel::registerBasic();
|
|
CVegetableBlendLayerModel::registerBasic();
|
|
CRootModel::registerBasic();
|
|
CPointLightModel::registerBasic();
|
|
CSegRemanence::registerBasic();
|
|
CQuadGridClipManager::registerBasic();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
// ***************************************************************************
|
|
CScene::CScene(bool bSmallScene) : LightTrav(bSmallScene)
|
|
{
|
|
HrcTrav.Scene= this;
|
|
ClipTrav.Scene= this;
|
|
LightTrav.Scene= this;
|
|
AnimDetailTrav.Scene= this;
|
|
LoadBalancingTrav.Scene= this;
|
|
RenderTrav.Scene= this;
|
|
|
|
_ShapeBank = NULL;
|
|
|
|
Root= NULL;
|
|
RootCluster= NULL;
|
|
SonsOfAncestorSkeletonModelGroup= NULL;
|
|
_QuadGridClipManager= NULL;
|
|
|
|
_CurrentTime = 0 ;
|
|
_EllapsedTime = 0 ;
|
|
_RealTime = 0 ;
|
|
_FirstAnimateCall = true ;
|
|
|
|
_LightingSystemEnabled= false;
|
|
_CoarseMeshLightingUpdate= 50;
|
|
|
|
_GlobalWindDirection.set(1,0,0);
|
|
// Default as Sithikt wants.
|
|
_GlobalWindPower= 0.2f;
|
|
|
|
// global manager (created in CDriverUser)
|
|
_LodCharacterManager= NULL;
|
|
_AsyncTextureManager= NULL;
|
|
|
|
_NumRender = 0;
|
|
|
|
_MaxSkeletonsInNotCLodForm= 20;
|
|
|
|
_FilterRenderFlags= ~0;
|
|
|
|
_NextRenderProfile= false;
|
|
|
|
// Init default _CoarseMeshManager
|
|
_CoarseMeshManager= new CCoarseMeshManager;
|
|
_CoarseMeshManager->setTextureFile (NL3D_SCENE_COARSE_MANAGER_TEXTURE);
|
|
|
|
// Update model list to NULL
|
|
_UpdateModelList= NULL;
|
|
|
|
_FlareContext = 0;
|
|
|
|
_ShadowMapTextureSize= NL3D_SCENE_DEFAULT_SHADOW_MAP_SIZE;
|
|
_ShadowMapBlurSize= NL3D_SCENE_DEFAULT_SHADOW_MAP_BLUR_SIZE;
|
|
_ShadowMapDistFadeStart= NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_START;
|
|
_ShadowMapDistFadeEnd= NL3D_SCENE_DEFAULT_SHADOW_MAP_DIST_FADE_END;
|
|
_ShadowMapMaxCasterInScreen= NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_IN_SCREEN;
|
|
_ShadowMapMaxCasterAround= NL3D_SCENE_DEFAULT_SHADOW_MAP_MAX_CASTER_AROUND;
|
|
_VisualCollisionManagerForShadow= NULL;
|
|
|
|
_WaterCallback = NULL;
|
|
_PolyDrawingCallback = NULL;
|
|
_IsRendering = false;
|
|
|
|
_FirstFlare = NULL;
|
|
_RenderedPart = UScene::RenderNothing;
|
|
//_WaterEnvMapRdr = NULL;
|
|
//_WaterEnvMap = new CTextureCube;
|
|
|
|
_WaterEnvMap = NULL;
|
|
|
|
_GlobalSystemTime= 0.0;
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::release()
|
|
{
|
|
// reset the _QuadGridClipManager, => unlink models, and delete clusters.
|
|
if( _QuadGridClipManager )
|
|
_QuadGridClipManager->reset();
|
|
|
|
// First, delete models.
|
|
set<CTransform*>::iterator it;
|
|
it= _Models.begin();
|
|
while( it!=_Models.end())
|
|
{
|
|
CTransform *tr= *it;
|
|
// Don't delete The Roots, because used, for instance in ~CSkeletonModel()
|
|
if(tr!=Root && tr!=RootCluster && tr!=SonsOfAncestorSkeletonModelGroup)
|
|
deleteModel(tr);
|
|
// temp erase from the list
|
|
else
|
|
_Models.erase(it);
|
|
// NB: important to take begin(), and not it++, cause ~CSkeletonModel() may delete ScriptSpawned models
|
|
it= _Models.begin();
|
|
}
|
|
|
|
// Then delete the roots
|
|
// reinsert
|
|
if(Root) _Models.insert(Root);
|
|
if(RootCluster) _Models.insert(RootCluster);
|
|
if(SonsOfAncestorSkeletonModelGroup) _Models.insert(SonsOfAncestorSkeletonModelGroup);
|
|
// delete in the reverse order of initDefaultRoots()
|
|
if(SonsOfAncestorSkeletonModelGroup)
|
|
{
|
|
deleteModel(SonsOfAncestorSkeletonModelGroup);
|
|
SonsOfAncestorSkeletonModelGroup= NULL;
|
|
}
|
|
if(RootCluster)
|
|
{
|
|
deleteModel(RootCluster);
|
|
RootCluster= NULL;
|
|
}
|
|
if(Root)
|
|
{
|
|
deleteModel(Root);
|
|
Root= NULL;
|
|
}
|
|
|
|
// No models at all.
|
|
_UpdateModelList= NULL;
|
|
|
|
// reset ptrs
|
|
_ShapeBank = NULL;
|
|
Root= NULL;
|
|
RootCluster= NULL;
|
|
SonsOfAncestorSkeletonModelGroup= NULL;
|
|
CurrentCamera= NULL;
|
|
_QuadGridClipManager= NULL;
|
|
ClipTrav.setQuadGridClipManager(NULL);
|
|
|
|
// DON'T reset the _LodCharacterManager, because it can be shared across scenes
|
|
/*
|
|
if(_LodCharacterManager)
|
|
_LodCharacterManager->reset();
|
|
*/
|
|
_LodCharacterManager= NULL;
|
|
|
|
// delete the coarseMeshManager
|
|
if(_CoarseMeshManager)
|
|
{
|
|
delete _CoarseMeshManager;
|
|
_CoarseMeshManager= NULL;
|
|
}
|
|
|
|
if(_GlobalInstanceGroup)
|
|
{
|
|
delete _GlobalInstanceGroup;
|
|
_GlobalInstanceGroup = NULL;
|
|
}
|
|
|
|
// delete the play list
|
|
_LMAnimsAuto.deleteAll();
|
|
}
|
|
// ***************************************************************************
|
|
CScene::~CScene()
|
|
{
|
|
release();
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::initDefaultRoots()
|
|
{
|
|
// Create and set root the default models.
|
|
Root= static_cast<CTransform*>(createModel(TransformId));
|
|
|
|
// The root is always freezed (never move).
|
|
Root->freeze();
|
|
|
|
// Init the instance group that represent the world
|
|
_GlobalInstanceGroup = new CInstanceGroup;
|
|
RootCluster= (CCluster*)createModel (ClusterId);
|
|
// unlink from hrc.
|
|
RootCluster->hrcUnlink();
|
|
RootCluster->Name = "ClusterRoot";
|
|
RootCluster->Group = _GlobalInstanceGroup;
|
|
_GlobalInstanceGroup->addCluster (RootCluster);
|
|
|
|
// init the ClipTrav.RootCluster.
|
|
ClipTrav.RootCluster = RootCluster;
|
|
|
|
// Create a SonsOfAncestorSkeletonModelGroup, for models which have a skeleton ancestor
|
|
SonsOfAncestorSkeletonModelGroup= static_cast<CRootModel*>(createModel(RootModelId));
|
|
// must unlink it from all traversals, because special, only used in CClipTrav::traverse()
|
|
SonsOfAncestorSkeletonModelGroup->hrcUnlink();
|
|
Root->clipDelChild(SonsOfAncestorSkeletonModelGroup);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::initQuadGridClipManager ()
|
|
{
|
|
// Init clip features.
|
|
if( !_QuadGridClipManager )
|
|
{
|
|
// create the model
|
|
_QuadGridClipManager= static_cast<CQuadGridClipManager*>(createModel(QuadGridClipManagerId));
|
|
// unlink it from hrc, and link it only to RootCluster.
|
|
// NB: hence the quadGridClipManager may be clipped by the cluster system
|
|
_QuadGridClipManager->hrcUnlink();
|
|
_QuadGridClipManager->clipUnlinkFromAll();
|
|
RootCluster->clipAddChild(_QuadGridClipManager);
|
|
|
|
// init _QuadGridClipManager.
|
|
_QuadGridClipManager->init(NL3D_QuadGridClipClusterSize,
|
|
NL3D_QuadGridClipNumDist,
|
|
NL3D_QuadGridClipMaxDist,
|
|
NL3D_QuadGridClipManagerRadiusMax);
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::render(bool doHrcPass)
|
|
{
|
|
beginPartRender();
|
|
renderPart(UScene::RenderAll, doHrcPass);
|
|
endPartRender();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::beginPartRender()
|
|
{
|
|
nlassert(!_IsRendering);
|
|
|
|
// Do not delete model during the rendering
|
|
// Also do not create model with CSkeletonSpawnScript model animation
|
|
_IsRendering = true;
|
|
_RenderedPart= UScene::RenderNothing;
|
|
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::endPartRender()
|
|
{
|
|
nlassert(_IsRendering);
|
|
|
|
// Delete model deleted during the rendering
|
|
_IsRendering = false;
|
|
uint i;
|
|
for (i=0; i<_ToDelete.size(); i++)
|
|
deleteModel (_ToDelete[i]);
|
|
_ToDelete.clear ();
|
|
|
|
// Special for SkeletonSpawnScript animation. create models spawned now
|
|
flushSSSModelRequests();
|
|
|
|
// Particle system handling (remove the resources of those which are too far, as their clusters may not have been parsed).
|
|
// Note that only a few of them are tested at each call
|
|
_ParticleSystemManager.refreshModels(ClipTrav.WorldFrustumPyramid, ClipTrav.CamPos);
|
|
|
|
// Waiting Instance handling
|
|
double deltaT = _DeltaSystemTimeBetweenRender;
|
|
clamp (deltaT, 0.01, 0.1);
|
|
updateWaitingInstances(deltaT);
|
|
|
|
// Reset profiling
|
|
_NextRenderProfile= false;
|
|
|
|
|
|
/*
|
|
uint64 total = PSStatsRegisterPSModelObserver +
|
|
PSStatsRemovePSModelObserver +
|
|
PSStatsUpdateOpacityInfos +
|
|
PSStatsUpdateLightingInfos +
|
|
PSStatsGetAABBox +
|
|
PSStatsReallocRsc +
|
|
PSStatsReleasePSPointer +
|
|
PSStatsRefreshRscDeletion +
|
|
PSStatsReleaseRsc +
|
|
PSStatsReleaseRscAndInvalidate +
|
|
PSStatsGetNumTriangles +
|
|
PSStatsCheckAgainstPyramid +
|
|
PSStatsTraverseAnimDetail +
|
|
PSStatsDoAnimate +
|
|
PSStatsTraverseRender +
|
|
PSStatsTraverseClip +
|
|
PSStatsCheckDestroyCondition +
|
|
PSStatsForceInstanciate +
|
|
PSStatsDoAnimatePart1 +
|
|
PSStatsDoAnimatePart2 +
|
|
PSStatsDoAnimatePart3 +
|
|
PSStatsTraverseAnimDetailPart1 +
|
|
PSStatsTraverseAnimDetailPart2 +
|
|
PSStatsTraverseAnimDetailPart3 +
|
|
PSStatsTraverseAnimDetailPart4 +
|
|
PSAnim1 +
|
|
PSAnim2+
|
|
PSAnim3+
|
|
PSAnim4+
|
|
PSAnim5+
|
|
PSAnim6+
|
|
PSAnim7+
|
|
PSAnim8+
|
|
PSAnim9+
|
|
PSAnim10+
|
|
PSAnim11;
|
|
|
|
|
|
if (((double) total / (double) NLMISC::CSystemInfo::getProcessorFrequency()) > 0.01)
|
|
{
|
|
nlinfo("***** PS STATS ****");
|
|
#define PS_STATS(var) \
|
|
nlinfo("time for " #var " = %.2f", (float) (1000 * ((double) var / (double) CSystemInfo::getProcessorFrequency())));
|
|
|
|
PS_STATS(PSStatsRegisterPSModelObserver)
|
|
PS_STATS(PSStatsRemovePSModelObserver)
|
|
PS_STATS(PSStatsUpdateOpacityInfos)
|
|
PS_STATS(PSStatsUpdateLightingInfos)
|
|
PS_STATS(PSStatsGetAABBox)
|
|
PS_STATS(PSStatsReallocRsc)
|
|
PS_STATS(PSStatsReleasePSPointer)
|
|
PS_STATS(PSStatsRefreshRscDeletion)
|
|
PS_STATS(PSStatsReleaseRsc)
|
|
PS_STATS(PSStatsReleaseRscAndInvalidate)
|
|
PS_STATS(PSStatsGetNumTriangles)
|
|
PS_STATS(PSStatsCheckAgainstPyramid)
|
|
PS_STATS(PSStatsTraverseAnimDetail)
|
|
PS_STATS(PSStatsDoAnimate)
|
|
PS_STATS(PSStatsTraverseRender)
|
|
PS_STATS(PSStatsTraverseClip)
|
|
PS_STATS(PSStatsClipSystemInstanciated);
|
|
PS_STATS(PSStatsClipSystemNotInstanciated);
|
|
PS_STATS(PSStatsClipSystemCheckAgainstPyramid);
|
|
PS_STATS(PSStatsInsertInVisibleList);
|
|
PS_STATS(PSStatsCheckDestroyCondition)
|
|
PS_STATS(PSStatsForceInstanciate)
|
|
PS_STATS(PSStatsDoAnimatePart1)
|
|
PS_STATS(PSStatsDoAnimatePart2)
|
|
PS_STATS(PSStatsDoAnimatePart3)
|
|
PS_STATS(PSStatsTraverseAnimDetailPart1)
|
|
PS_STATS(PSStatsTraverseAnimDetailPart2)
|
|
PS_STATS(PSStatsTraverseAnimDetailPart3)
|
|
PS_STATS(PSStatsTraverseAnimDetailPart4)
|
|
PS_STATS(PSAnim1)
|
|
PS_STATS(PSAnim2)
|
|
PS_STATS(PSAnim3)
|
|
PS_STATS(PSAnim4)
|
|
PS_STATS(PSAnim5)
|
|
PS_STATS(PSAnim6)
|
|
PS_STATS(PSAnim7)
|
|
PS_STATS(PSAnim8)
|
|
PS_STATS(PSAnim9)
|
|
PS_STATS(PSAnim10)
|
|
PS_STATS(PSAnim11)
|
|
PS_STATS(PSStatsZonePlane)
|
|
PS_STATS(PSStatsZoneSphere)
|
|
PS_STATS(PSStatsZoneDisc)
|
|
PS_STATS(PSStatsZoneRectangle)
|
|
PS_STATS(PSStatsZoneCylinder)
|
|
PS_STATS(PSMotion1)
|
|
PS_STATS(PSMotion2)
|
|
PS_STATS(PSMotion3)
|
|
PS_STATS(PSMotion4)
|
|
PS_STATS(PSStatCollision)
|
|
PS_STATS(PSStatEmit)
|
|
PS_STATS(PSStatRender)
|
|
|
|
|
|
nlinfo("num do animate = %d", (int) PSStatsNumDoAnimateCalls);
|
|
|
|
nlinfo("Max et = %.2f", PSMaxET);
|
|
nlinfo("Max ps nb pass = %d", (int) PSMaxNBPass);
|
|
|
|
PS_STATS(total)
|
|
|
|
}
|
|
|
|
PSStatsRegisterPSModelObserver = 0;
|
|
PSStatsRemovePSModelObserver = 0;
|
|
PSStatsUpdateOpacityInfos = 0;
|
|
PSStatsUpdateLightingInfos = 0;
|
|
PSStatsGetAABBox = 0;
|
|
PSStatsReallocRsc = 0;
|
|
PSStatsReleasePSPointer = 0;
|
|
PSStatsRefreshRscDeletion = 0;
|
|
PSStatsReleaseRsc = 0;
|
|
PSStatsReleaseRscAndInvalidate = 0;
|
|
PSStatsGetNumTriangles = 0;
|
|
PSStatsCheckAgainstPyramid = 0;
|
|
PSStatsTraverseAnimDetail = 0;
|
|
PSStatsDoAnimate = 0;
|
|
PSStatsTraverseRender = 0;
|
|
PSStatsTraverseClip = 0;
|
|
PSStatsCheckDestroyCondition = 0;
|
|
PSStatsForceInstanciate = 0;
|
|
PSStatsClipSystemInstanciated = 0;
|
|
PSStatsClipSystemNotInstanciated = 0;
|
|
PSStatsClipSystemCheckAgainstPyramid = 0;
|
|
PSStatsInsertInVisibleList = 0;
|
|
PSStatsDoAnimatePart1 = 0;
|
|
PSStatsDoAnimatePart2 = 0;
|
|
PSStatsDoAnimatePart3 = 0;
|
|
PSStatsTraverseAnimDetailPart1 = 0;
|
|
PSStatsTraverseAnimDetailPart2 = 0;
|
|
PSStatsTraverseAnimDetailPart3 = 0;
|
|
PSStatsTraverseAnimDetailPart4 = 0;
|
|
PSStatsNumDoAnimateCalls = 0;
|
|
PSAnim1 = 0;
|
|
PSAnim2 = 0;
|
|
PSAnim3 = 0;
|
|
PSAnim4 = 0;
|
|
PSAnim5 = 0;
|
|
PSAnim6 = 0;
|
|
PSAnim7 = 0;
|
|
PSAnim8 = 0;
|
|
PSAnim9 = 0;
|
|
PSAnim10 = 0;
|
|
PSAnim11 = 0;
|
|
PSMaxET = 0.f;
|
|
PSMaxNBPass = 0;
|
|
PSStatsZonePlane = 0;
|
|
PSStatsZoneSphere = 0;
|
|
PSStatsZoneDisc = 0;
|
|
PSStatsZoneRectangle = 0;
|
|
PSStatsZoneCylinder = 0;
|
|
PSMotion1 = 0;
|
|
PSMotion2 = 0;
|
|
PSMotion3 = 0;
|
|
PSMotion4 = 0;
|
|
PSStatCollision = 0;
|
|
PSStatEmit = 0;
|
|
PSStatRender = 0;
|
|
*/
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::renderPart(UScene::TRenderPart rp, bool doHrcPass)
|
|
{
|
|
nlassert(_IsRendering);
|
|
|
|
// if nothing (????), abort
|
|
if(rp==UScene::RenderNothing)
|
|
return;
|
|
|
|
// If part asked already rendered, abort
|
|
nlassert((rp & _RenderedPart) == 0); // cannot render the same part twice during a render
|
|
|
|
// if first part to be rendered, do the start stuff
|
|
if (_RenderedPart == UScene::RenderNothing)
|
|
{
|
|
// update water envmap
|
|
//updateWaterEnvmap();
|
|
RenderTrav.clearWaterModelList();
|
|
_FirstFlare = NULL;
|
|
|
|
double fNewGlobalSystemTime = NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime());
|
|
if(_GlobalSystemTime==0)
|
|
_DeltaSystemTimeBetweenRender= 0.020;
|
|
else
|
|
_DeltaSystemTimeBetweenRender= fNewGlobalSystemTime - _GlobalSystemTime;
|
|
_GlobalSystemTime = fNewGlobalSystemTime;
|
|
//
|
|
++ _NumRender;
|
|
//
|
|
nlassert(CurrentCamera);
|
|
|
|
// update models.
|
|
updateModels();
|
|
|
|
// Use the camera to setup Clip / Render pass.
|
|
float left, right, bottom, top, znear, zfar;
|
|
CurrentCamera->getFrustum(left, right, bottom, top, znear, zfar);
|
|
|
|
// setup basic camera.
|
|
ClipTrav.setFrustum(left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
|
|
|
|
RenderTrav.setFrustum (left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
|
|
RenderTrav.setViewport (_Viewport);
|
|
|
|
LoadBalancingTrav.setFrustum (left, right, bottom, top, znear, zfar, CurrentCamera->isPerspective());
|
|
|
|
|
|
// Set Infos for cliptrav.
|
|
ClipTrav.Camera = CurrentCamera;
|
|
ClipTrav.setQuadGridClipManager (_QuadGridClipManager);
|
|
|
|
|
|
// **** For all render traversals, traverse them (except the Hrc one), in ascending order.
|
|
if( doHrcPass )
|
|
HrcTrav.traverse();
|
|
|
|
// Set Cam World Matrix for all trav that need it
|
|
ClipTrav.setCamMatrix(CurrentCamera->getWorldMatrix());
|
|
RenderTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
|
|
LoadBalancingTrav.setCamMatrix (CurrentCamera->getWorldMatrix());
|
|
|
|
|
|
// clip
|
|
ClipTrav.traverse();
|
|
// animDetail
|
|
AnimDetailTrav.traverse();
|
|
// loadBalance
|
|
LoadBalancingTrav.traverse();
|
|
//
|
|
_ParticleSystemManager.processAnimate(_EllapsedTime); // deals with permanently animated particle systems
|
|
// Light
|
|
LightTrav.traverse();
|
|
}
|
|
|
|
// render
|
|
RenderTrav.traverse(rp, _RenderedPart == UScene::RenderNothing);
|
|
// Always must clear shadow caster (if render did not work because of IDriver::isLost())
|
|
RenderTrav.getShadowMapManager().clearAllShadowCasters();
|
|
|
|
// render flare
|
|
if (rp & UScene::RenderFlare)
|
|
{
|
|
if (_FirstFlare)
|
|
{
|
|
IDriver *drv = getDriver();
|
|
CFlareModel::updateOcclusionQueryBegin(drv);
|
|
CFlareModel *currFlare = _FirstFlare;
|
|
do
|
|
{
|
|
currFlare->updateOcclusionQuery(drv);
|
|
currFlare = currFlare->Next;
|
|
}
|
|
while(currFlare);
|
|
CFlareModel::updateOcclusionQueryEnd(drv);
|
|
}
|
|
}
|
|
_RenderedPart = (UScene::TRenderPart) (_RenderedPart | rp);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::updateWaitingInstances(double systemTimeEllapsed)
|
|
{
|
|
// First set up max AGP upload
|
|
double fMaxBytesToUp = 100 * 256 * 256 * systemTimeEllapsed;
|
|
_ShapeBank->setMaxBytesToUpload ((uint32)fMaxBytesToUp);
|
|
// Parse all the waiting instance
|
|
_ShapeBank->processWaitingShapes (); // Process waiting shapes load shape, texture, and lightmaps
|
|
// and upload all maps to VRAM pieces by pieces
|
|
TWaitingInstancesMMap::iterator wimmIt = _WaitingInstances.begin();
|
|
while( wimmIt != _WaitingInstances.end() )
|
|
{
|
|
CShapeBank::TShapeState st = _ShapeBank->getPresentState (wimmIt->first);
|
|
if (st == CShapeBank::AsyncLoad_Error)
|
|
{
|
|
// Delete the waiting instance - Nobody can be informed of that...
|
|
TWaitingInstancesMMap::iterator itDel= wimmIt;
|
|
++wimmIt;
|
|
_WaitingInstances.erase(itDel);
|
|
}
|
|
else if (st == CShapeBank::Present)
|
|
{
|
|
// Then create a reference to the shape
|
|
*(wimmIt->second) = _ShapeBank->addRef(wimmIt->first)->createInstance (*this);
|
|
// Delete the waiting instance
|
|
TWaitingInstancesMMap::iterator itDel= wimmIt;
|
|
++wimmIt;
|
|
_WaitingInstances.erase(itDel);
|
|
}
|
|
else // st == CShapeBank::NotPresent or loading
|
|
{
|
|
++wimmIt;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::setDriver(IDriver *drv)
|
|
{
|
|
RenderTrav.setDriver(drv);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
IDriver *CScene::getDriver() const
|
|
{
|
|
return (const_cast<CScene*>(this))->RenderTrav.getDriver();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// Shape mgt.
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
// ***************************************************************************
|
|
|
|
void CScene::setShapeBank(CShapeBank*pShapeBank)
|
|
{
|
|
_ShapeBank = pShapeBank;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
CTransformShape *CScene::createInstance(const string &shapeName)
|
|
{
|
|
// We must attach a bank to the scene (a ShapeBank handle the shape caches and
|
|
// the creation/deletion of the instances)
|
|
nlassert( _ShapeBank != NULL );
|
|
|
|
// If the shape is not present in the bank
|
|
if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
|
|
{
|
|
// Load it from file
|
|
_ShapeBank->load( shapeName );
|
|
if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
// Then create a reference to the shape
|
|
CTransformShape *pTShp = _ShapeBank->addRef( shapeName )->createInstance(*this);
|
|
if (pTShp) pTShp->setDistMax(pTShp->Shape->getDistMax());
|
|
|
|
// Look if this instance get lightmap information
|
|
#if defined(__GNUC__) && __GNUC__ < 3
|
|
CMeshBase *pMB = (CMeshBase*)((IShape*)(pTShp->Shape));
|
|
#else // not GNUC
|
|
CMeshBase *pMB = dynamic_cast<CMeshBase*>((IShape*)(pTShp->Shape));
|
|
#endif // not GNUC
|
|
CMeshBaseInstance *pMBI = dynamic_cast<CMeshBaseInstance*>( pTShp );
|
|
if( ( pMB != NULL ) && ( pMBI != NULL ) )
|
|
{
|
|
// Init lightmap information
|
|
pMBI->initAnimatedLightIndex (*this);
|
|
|
|
// Auto animations
|
|
//==========================
|
|
|
|
if (_AutomaticAnimationSet)
|
|
{
|
|
if (pMB->getAutoAnim())
|
|
{
|
|
|
|
std::string animName = toLower(CFile::getFilenameWithoutExtension(shapeName));
|
|
uint animID = _AutomaticAnimationSet->getAnimationIdByName(animName);
|
|
if (animID != CAnimationSet::NotFound)
|
|
{
|
|
CChannelMixer *chanMix = new CChannelMixer;
|
|
chanMix->setAnimationSet((CAnimationSet *) _AutomaticAnimationSet);
|
|
chanMix->setSlotAnimation(0, animID);
|
|
|
|
pMBI->registerToChannelMixer(chanMix, "");
|
|
// Gives this object ownership of the channel mixer so we don't need to keep track of it
|
|
pMBI->setChannelMixerOwnerShip(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CLandscapeModel *pLM = dynamic_cast<CLandscapeModel*>( pTShp );
|
|
if( pLM != NULL )
|
|
{
|
|
// Init lightmap information
|
|
pLM->Landscape.initAnimatedLightIndex (*this);
|
|
}
|
|
|
|
return pTShp;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CScene::createInstanceAsync(const string &shapeName, CTransformShape **pInstance, const NLMISC::CVector &position, uint selectedTexture)
|
|
{
|
|
// We must attach a bank to the scene (a ShapeBank handle the shape caches and
|
|
// the creation/deletion of the instances)
|
|
nlassert( _ShapeBank != NULL );
|
|
*pInstance = NULL;
|
|
// Add the instance request
|
|
_WaitingInstances.insert(TWaitingInstancesMMap::value_type(shapeName,pInstance));
|
|
// If the shape is not present in the bank
|
|
if (_ShapeBank->getPresentState( shapeName ) != CShapeBank::Present)
|
|
{
|
|
// Load it from file asynchronously
|
|
_ShapeBank->loadAsync( toLower(shapeName), getDriver(), position, NULL, selectedTexture);
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::deleteInstance(CTransformShape *pTrfmShp)
|
|
{
|
|
IShape *pShp = NULL;
|
|
if( pTrfmShp == NULL )
|
|
return;
|
|
|
|
pShp = pTrfmShp->Shape;
|
|
|
|
deleteModel( pTrfmShp );
|
|
|
|
if (pShp)
|
|
{
|
|
// Even if model already deleted by smarptr the release function works
|
|
_ShapeBank->release( pShp );
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::animate( TGlobalAnimationTime atTime )
|
|
{
|
|
// todo hulud remove
|
|
if (_FirstAnimateCall)
|
|
{
|
|
_InitTime = atTime;
|
|
_RealTime = atTime;
|
|
// dummy value for first frame
|
|
_EllapsedTime = 0.01f ;
|
|
_FirstAnimateCall = false ;
|
|
}
|
|
else
|
|
{
|
|
_EllapsedTime = (float) (atTime - _RealTime);
|
|
//nlassert(_EllapsedTime >= 0);
|
|
if (_EllapsedTime < 0.0f) // NT WorkStation PATCH (Yes you are not dreaming
|
|
_EllapsedTime = 0.01f; // deltaTime can be less than zero!!)
|
|
_EllapsedTime = fabsf(_EllapsedTime);
|
|
_RealTime = atTime ;
|
|
_CurrentTime += _EllapsedTime;
|
|
}
|
|
|
|
_LMAnimsAuto.animate( atTime );
|
|
|
|
// Change PointLightFactors of all pointLights in registered Igs.
|
|
//----------------
|
|
|
|
// First list all current AnimatedLightmaps (for faster vector iteration per ig)
|
|
const uint count = (uint)_AnimatedLightPtr.size ();
|
|
uint i;
|
|
for (i=0; i<count; i++)
|
|
{
|
|
// Blend final colors
|
|
_AnimatedLightPtr[i]->updateGroupColors (*this);
|
|
}
|
|
|
|
// For all registered igs.
|
|
ItAnimatedIgSet itAnIgSet;
|
|
for(itAnIgSet= _AnimatedIgSet.begin(); itAnIgSet!=_AnimatedIgSet.end(); itAnIgSet++)
|
|
{
|
|
CInstanceGroup *ig= *itAnIgSet;
|
|
|
|
// Set the light factor
|
|
ig->setPointLightFactor(*this);
|
|
}
|
|
|
|
// Rendered part are invalidate
|
|
_RenderedPart = UScene::RenderNothing;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
float CScene::getNbFaceAsked () const
|
|
{
|
|
return LoadBalancingTrav.getNbFaceAsked ();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setGroupLoadMaxPolygon(const std::string &group, uint nFaces)
|
|
{
|
|
nFaces= max(nFaces, (uint)1);
|
|
LoadBalancingTrav.setGroupNbFaceWanted(group, nFaces);
|
|
}
|
|
// ***************************************************************************
|
|
uint CScene::getGroupLoadMaxPolygon(const std::string &group)
|
|
{
|
|
return LoadBalancingTrav.getGroupNbFaceWanted(group);
|
|
}
|
|
// ***************************************************************************
|
|
float CScene::getGroupNbFaceAsked (const std::string &group) const
|
|
{
|
|
return LoadBalancingTrav.getGroupNbFaceAsked(group);
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setPolygonBalancingMode(TPolygonBalancingMode polBalMode)
|
|
{
|
|
LoadBalancingTrav.PolygonBalancingMode= (CLoadBalancingGroup::TPolygonBalancingMode)(uint)polBalMode;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
CScene::TPolygonBalancingMode CScene::getPolygonBalancingMode() const
|
|
{
|
|
return (CScene::TPolygonBalancingMode)(uint)LoadBalancingTrav.PolygonBalancingMode;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::setLayersRenderingOrder(bool directOrder /*= true*/)
|
|
{
|
|
RenderTrav.setLayersRenderingOrder(directOrder);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CScene::getLayersRenderingOrder() const
|
|
{
|
|
return RenderTrav.getLayersRenderingOrder();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CParticleSystemManager &CScene::getParticleSystemManager()
|
|
{
|
|
return _ParticleSystemManager;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::enableElementRender(UScene::TRenderFilter elt, bool state)
|
|
{
|
|
if(state)
|
|
_FilterRenderFlags|= (uint32)elt;
|
|
else
|
|
_FilterRenderFlags&= ~(uint32)elt;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// Lighting Mgt.
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::enableLightingSystem(bool enable)
|
|
{
|
|
_LightingSystemEnabled= enable;
|
|
|
|
// Set to RenderTrav and LightTrav
|
|
RenderTrav.LightingSystemEnabled= _LightingSystemEnabled;
|
|
LightTrav.LightingSystemEnabled= _LightingSystemEnabled;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setAmbientGlobal(NLMISC::CRGBA ambient)
|
|
{
|
|
RenderTrav.AmbientGlobal= ambient;
|
|
}
|
|
void CScene::setSunAmbient(NLMISC::CRGBA ambient)
|
|
{
|
|
RenderTrav.SunAmbient= ambient;
|
|
}
|
|
void CScene::setSunDiffuse(NLMISC::CRGBA diffuse)
|
|
{
|
|
RenderTrav.SunDiffuse= diffuse;
|
|
}
|
|
void CScene::setSunSpecular(NLMISC::CRGBA specular)
|
|
{
|
|
RenderTrav.SunSpecular= specular;
|
|
}
|
|
void CScene::setSunDirection(const NLMISC::CVector &direction)
|
|
{
|
|
RenderTrav.setSunDirection(direction);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
NLMISC::CRGBA CScene::getAmbientGlobal() const
|
|
{
|
|
return RenderTrav.AmbientGlobal;
|
|
}
|
|
NLMISC::CRGBA CScene::getSunAmbient() const
|
|
{
|
|
return RenderTrav.SunAmbient;
|
|
}
|
|
NLMISC::CRGBA CScene::getSunDiffuse() const
|
|
{
|
|
return RenderTrav.SunDiffuse;
|
|
}
|
|
NLMISC::CRGBA CScene::getSunSpecular() const
|
|
{
|
|
return RenderTrav.SunSpecular;
|
|
}
|
|
NLMISC::CVector CScene::getSunDirection() const
|
|
{
|
|
return RenderTrav.getSunDirection();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setMaxLightContribution(uint nlights)
|
|
{
|
|
LightTrav.LightingManager.setMaxLightContribution(nlights);
|
|
}
|
|
uint CScene::getMaxLightContribution() const
|
|
{
|
|
return LightTrav.LightingManager.getMaxLightContribution();
|
|
}
|
|
|
|
void CScene::setLightTransitionThreshold(float lightTransitionThreshold)
|
|
{
|
|
LightTrav.LightingManager.setLightTransitionThreshold(lightTransitionThreshold);
|
|
}
|
|
float CScene::getLightTransitionThreshold() const
|
|
{
|
|
return LightTrav.LightingManager.getLightTransitionThreshold();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::addInstanceGroupForLightAnimation(CInstanceGroup *ig)
|
|
{
|
|
nlassert( ig );
|
|
nlassert( _AnimatedIgSet.find(ig) == _AnimatedIgSet.end() );
|
|
_AnimatedIgSet.insert(ig);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::removeInstanceGroupForLightAnimation(CInstanceGroup *ig)
|
|
{
|
|
nlassert( ig );
|
|
ItAnimatedIgSet itIg= _AnimatedIgSet.find(ig);
|
|
if ( itIg != _AnimatedIgSet.end() )
|
|
_AnimatedIgSet.erase(itIg);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setCoarseMeshLightingUpdate(uint8 period)
|
|
{
|
|
_CoarseMeshLightingUpdate= max((uint8)1, period);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
/// Weather mgt
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
// ***************************************************************************
|
|
void CScene::setGlobalWindPower(float gwp)
|
|
{
|
|
_GlobalWindPower= gwp;
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::setGlobalWindDirection(const CVector &gwd)
|
|
{
|
|
_GlobalWindDirection= gwd;
|
|
_GlobalWindDirection.z= 0;
|
|
_GlobalWindDirection.normalize();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
/// Private
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
// ***************************************************************************
|
|
CScene::ItSkeletonModelList CScene::appendSkeletonModelToList(CSkeletonModel *skel)
|
|
{
|
|
_SkeletonModelList.push_front(skel);
|
|
return _SkeletonModelList.begin();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::eraseSkeletonModelToList(CScene::ItSkeletonModelList it)
|
|
{
|
|
_SkeletonModelList.erase(it);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::registerShadowCasterToList(CTransform *sc)
|
|
{
|
|
nlassert(sc);
|
|
_ShadowCasterList.push_front(sc);
|
|
sc->_ItShadowCasterInScene= _ShadowCasterList.begin();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::unregisterShadowCasterToList(CTransform *sc)
|
|
{
|
|
nlassert(sc);
|
|
_ShadowCasterList.erase(sc->_ItShadowCasterInScene);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// Old CMOT integrated methods
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
|
|
// ***************************************************************************
|
|
set<CScene::CModelEntry> CScene::_RegModels;
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::registerModel(const CClassId &idModel, const CClassId &idModelBase, CTransform* (*creator)())
|
|
{
|
|
nlassert(idModel!=CClassId::Null);
|
|
nlassert(creator);
|
|
// idModelBase may be Null...
|
|
|
|
CModelEntry e;
|
|
e.BaseModelId= idModelBase;
|
|
e.ModelId= idModel;
|
|
e.Creator= creator;
|
|
|
|
// Insert/replace e.
|
|
_RegModels.erase(e);
|
|
_RegModels.insert(e);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
CTransform *CScene::createModel(const CClassId &idModel)
|
|
{
|
|
nlassert(idModel!=CClassId::Null);
|
|
|
|
CModelEntry e;
|
|
e.ModelId= idModel;
|
|
set<CModelEntry>::iterator itModel;
|
|
itModel= _RegModels.find(e);
|
|
|
|
if(itModel==_RegModels.end())
|
|
{
|
|
nlstop; // Warning, CScene::registerBasics () has not been called !
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
CTransform *m= (*itModel).Creator();
|
|
if(!m) return NULL;
|
|
|
|
// Set the owner for the model.
|
|
m->_OwnerScene= this;
|
|
|
|
// link model to Root in HRC and in clip. NB: if exist!! (case for the Root and RootCluster :) )
|
|
if(Root)
|
|
{
|
|
Root->hrcLinkSon(m);
|
|
Root->clipAddChild(m);
|
|
}
|
|
|
|
// Insert the model into the set.
|
|
_Models.insert(m);
|
|
|
|
// By default the model is update() in CScene::updateModels().
|
|
m->linkToUpdateList();
|
|
|
|
// Once the model is correclty created, finish init him.
|
|
m->initModel();
|
|
|
|
// Ensure all the Traversals has enough space for visible list.
|
|
ClipTrav.reserveVisibleList((uint)_Models.size());
|
|
AnimDetailTrav.reserveVisibleList((uint)_Models.size());
|
|
LoadBalancingTrav.reserveVisibleList((uint)_Models.size());
|
|
LightTrav.reserveLightedList((uint)_Models.size());
|
|
RenderTrav.reserveRenderList((uint)_Models.size());
|
|
|
|
return m;
|
|
}
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::deleteModel(CTransform *model)
|
|
{
|
|
if(model==NULL)
|
|
return;
|
|
|
|
// No model delete during the render
|
|
if (_IsRendering)
|
|
{
|
|
// add ot list of object to delete
|
|
_ToDelete.push_back (model);
|
|
// remove this object from the RenderTrav, hence it won't be displayed
|
|
// still animDetail/Light/LoadBalance it. This is unuseful, but very rare
|
|
// and I prefer doing like this than to add a NULL ptr Test in each Traversal (which I then must do in CRenderTrav)
|
|
RenderTrav.removeRenderModel(model);
|
|
}
|
|
// standard delete
|
|
else
|
|
{
|
|
set<CTransform*>::iterator it= _Models.find(model);
|
|
if(it!=_Models.end())
|
|
{
|
|
delete *it;
|
|
_Models.erase(it);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::updateModels()
|
|
{
|
|
// check all the models which must be checked.
|
|
CTransform *model= _UpdateModelList;
|
|
CTransform *next;
|
|
while( model )
|
|
{
|
|
// next to update. get next now, because model->update() may remove model from the list.
|
|
next= model->_NextModelToUpdate;
|
|
|
|
// update the model.
|
|
model->update();
|
|
|
|
// next.
|
|
model= next;
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setLightGroupColor(uint lightmapGroup, NLMISC::CRGBA color)
|
|
{
|
|
// If too small, resize with white
|
|
if (lightmapGroup >= _LightGroupColor.size ())
|
|
{
|
|
_LightGroupColor.resize (lightmapGroup+1, CRGBA::White);
|
|
}
|
|
|
|
// Set the color
|
|
_LightGroupColor[lightmapGroup] = color;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
sint CScene::getAnimatedLightNameToIndex (const std::string &name) const
|
|
{
|
|
std::map<std::string, uint>::const_iterator ite = _AnimatedLightNameToIndex.find (name);
|
|
if (ite != _AnimatedLightNameToIndex.end ())
|
|
return (sint)ite->second;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setAutomaticAnimationSet(CAnimationSet *as)
|
|
{
|
|
// Backup the animation set
|
|
_AutomaticAnimationSet = as;
|
|
|
|
// Delete all auto lightmap animations
|
|
_LMAnimsAuto.deleteAll();
|
|
_AnimatedLightNameToIndex.clear();
|
|
_AnimatedLight.clear();
|
|
_AnimatedLightPtr.clear();
|
|
_LightGroupColor.clear();
|
|
|
|
// Register each animation as lightmap
|
|
const uint count = _AutomaticAnimationSet->getNumAnimation();
|
|
uint i;
|
|
for (i=0; i<count; i++)
|
|
{
|
|
// Pointer on the animation
|
|
CAnimation *pAnim = _AutomaticAnimationSet->getAnimation(i);
|
|
|
|
/* uint nAnimNb;
|
|
// Reset the automatic animation if no animation wanted
|
|
if( pAnim == NULL )
|
|
{
|
|
_AnimatedLight.clear();
|
|
_AnimatedLightPtr.clear();
|
|
_AnimatedLightNameToIndex.clear();
|
|
nAnimNb = _LightmapAnimations.getAnimationIdByName("Automatic");
|
|
if( nAnimNb != CAnimationSet::NotFound )
|
|
{
|
|
CAnimation *anim = _LightmapAnimations.getAnimation( nAnimNb );
|
|
delete anim;
|
|
}
|
|
_LightmapAnimations.reset();
|
|
_LMAnimsAuto.deleteAll();
|
|
return;
|
|
}
|
|
*/
|
|
|
|
set<string> setTrackNames;
|
|
pAnim->getTrackNames( setTrackNames );
|
|
|
|
// nAnimNb = _LightmapAnimations.addAnimation( "Automatic", pAnim );
|
|
// _LightmapAnimations.build();
|
|
|
|
set<string>::iterator itSel = setTrackNames.begin();
|
|
while ( itSel != setTrackNames.end() )
|
|
{
|
|
string ate = *itSel;
|
|
if( strncmp( itSel->c_str(), "LightmapController.", 19 ) == 0 )
|
|
{
|
|
// The light name
|
|
const char *lightName = strrchr ((*itSel).c_str (), '.')+1;
|
|
|
|
// Light animation doesn't exist ?
|
|
if (_AnimatedLightNameToIndex.find (lightName) == _AnimatedLightNameToIndex.end())
|
|
{
|
|
// Channel mixer for light anim
|
|
CChannelMixer *cm = new CChannelMixer();
|
|
cm->setAnimationSet( _AutomaticAnimationSet );
|
|
|
|
// Add an automatic animation
|
|
_AnimatedLight.push_back ( CAnimatedLightmap ((uint)_LightGroupColor.size ()) );
|
|
_AnimatedLightPtr.push_back ( &_AnimatedLight.back () );
|
|
_AnimatedLightNameToIndex.insert ( std::map<std::string, uint>::value_type (lightName, (uint32)_AnimatedLightPtr.size ()-1 ) );
|
|
CAnimatedLightmap &animLM = _AnimatedLight.back ();
|
|
animLM.setName( *itSel );
|
|
|
|
cm->addChannel( animLM.getName(), &animLM, animLM.getValue(CAnimatedLightmap::FactorValue),
|
|
animLM.getDefaultTrack(CAnimatedLightmap::FactorValue), CAnimatedLightmap::FactorValue,
|
|
CAnimatedLightmap::OwnerBit, false);
|
|
|
|
// Animated lightmap playlist
|
|
CAnimationPlaylist *pl = new CAnimationPlaylist();
|
|
pl->setAnimation( 0, i );
|
|
pl->setWrapMode( 0, CAnimationPlaylist::Repeat );
|
|
_LMAnimsAuto.addPlaylist(pl,cm);
|
|
}
|
|
}
|
|
++itSel;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
/// Misc
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
// ***************************************************************************
|
|
void CScene::profileNextRender()
|
|
{
|
|
_NextRenderProfile= true;
|
|
|
|
// Reset All Stats.
|
|
BenchRes.reset();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapTextureSize(uint size)
|
|
{
|
|
size= max(size, 2U);
|
|
size= raiseToNextPowerOf2(size);
|
|
_ShadowMapTextureSize= size;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapBlurSize(uint bs)
|
|
{
|
|
_ShadowMapBlurSize= bs;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::enableShadowPolySmooth(bool enable)
|
|
{
|
|
RenderTrav.getShadowMapManager().enableShadowPolySmooth(enable);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CScene::getEnableShadowPolySmooth() const
|
|
{
|
|
return RenderTrav.getShadowMapManager().getEnableShadowPolySmooth();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapDistFadeStart(float dist)
|
|
{
|
|
_ShadowMapDistFadeStart= max(0.f, dist);
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapDistFadeEnd(float dist)
|
|
{
|
|
_ShadowMapDistFadeEnd= max(0.f, dist);
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapMaxCasterInScreen(uint num)
|
|
{
|
|
_ShadowMapMaxCasterInScreen= num;
|
|
}
|
|
// ***************************************************************************
|
|
void CScene::setShadowMapMaxCasterAround(uint num)
|
|
{
|
|
_ShadowMapMaxCasterAround= num;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup *CScene::findCameraClusterSystemFromRay(CInstanceGroup *startClusterSystem,
|
|
const NLMISC::CVector &startPos, NLMISC::CVector &endPos)
|
|
{
|
|
CInstanceGroup *resultCS= NULL;
|
|
|
|
CClipTrav &clipTrav= getClipTrav();
|
|
|
|
// **** Search all cluster where the startPos is in
|
|
static vector<CCluster*> vCluster;
|
|
vCluster.clear();
|
|
|
|
bool bInWorld = true;
|
|
clipTrav.Accel.select (startPos, startPos);
|
|
CQuadGrid<CCluster*>::CIterator itAcc = clipTrav.Accel.begin();
|
|
while (itAcc != clipTrav.Accel.end())
|
|
{
|
|
CCluster *pCluster = *itAcc;
|
|
if( pCluster->Group == startClusterSystem &&
|
|
pCluster->isIn (startPos) )
|
|
{
|
|
vCluster.push_back (pCluster);
|
|
bInWorld = false;
|
|
}
|
|
++itAcc;
|
|
}
|
|
if (bInWorld)
|
|
{
|
|
vCluster.push_back (RootCluster);
|
|
}
|
|
|
|
// **** Do a traverse starting from each start cluser, clipping the ray instead of the camera pyramid
|
|
uint i;
|
|
static vector<CCluster*> vClusterVisited;
|
|
vClusterVisited.clear();
|
|
for(i=0;i<vCluster.size();i++)
|
|
{
|
|
vCluster[i]->cameraRayClip(startPos, endPos, vClusterVisited);
|
|
}
|
|
|
|
// **** From each cluster, select possible clusterSystem
|
|
static vector<CInstanceGroup*> possibleClusterSystem;
|
|
possibleClusterSystem.clear();
|
|
for(i=0;i<vClusterVisited.size();i++)
|
|
{
|
|
// select only cluster where the EndPos lies in. Important else in landscape, we'll always say
|
|
// that we are in a Son Cluster.
|
|
if(vClusterVisited[i]->isIn(endPos))
|
|
{
|
|
CInstanceGroup *cs= vClusterVisited[i]->Group;
|
|
// insert if not exist (NB: 1,2 possible clusterSystem so O(N2) is OK)
|
|
uint j;
|
|
for(j=0;j<possibleClusterSystem.size();j++)
|
|
{
|
|
if(possibleClusterSystem[j]==cs)
|
|
break;
|
|
}
|
|
if(j==possibleClusterSystem.size())
|
|
possibleClusterSystem.push_back(cs);
|
|
}
|
|
}
|
|
|
|
// If no cluster found, then we may be in a "Data Error case".
|
|
// In this case, ensure the Camera position in a cluster
|
|
if(possibleClusterSystem.empty())
|
|
{
|
|
CCluster *bestCluster= NULL;
|
|
float shortDist= FLT_MAX;
|
|
|
|
for(i=0;i<vClusterVisited.size();i++)
|
|
{
|
|
// if the ray is at least partially in this cluster
|
|
CVector a= startPos;
|
|
CVector b= endPos;
|
|
if(vClusterVisited[i]->clipSegment(a, b))
|
|
{
|
|
float dist= (endPos - b).norm();
|
|
if(dist<shortDist)
|
|
{
|
|
bestCluster= vClusterVisited[i];
|
|
shortDist= dist;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if found
|
|
if(bestCluster)
|
|
{
|
|
// append the best one to the possible Cluster System
|
|
possibleClusterSystem.push_back(bestCluster->Group);
|
|
|
|
// and modify endPos, so the camera will really lies into this cluster
|
|
const float threshold= 0.05f;
|
|
shortDist+= threshold;
|
|
// must not goes more than startPos!
|
|
float rayDist= (startPos - endPos).norm();
|
|
shortDist= min(shortDist, rayDist);
|
|
endPos+= (startPos - endPos).normed() * shortDist;
|
|
}
|
|
}
|
|
|
|
// NB: still possible that the possibleClusterSystem is empty, if not in any cluster for instance :)
|
|
|
|
|
|
// **** From each possible clusterSystem, select the one that is the lower in hierarchy
|
|
// common case
|
|
if(possibleClusterSystem.empty())
|
|
resultCS= NULL;
|
|
else if(possibleClusterSystem.size()==1)
|
|
{
|
|
// if it is the rootCluster set NULL (should have the same behavior but do like standard case)
|
|
if(possibleClusterSystem[0]==RootCluster->getClusterSystem())
|
|
resultCS= NULL;
|
|
// set this cluster system
|
|
else
|
|
resultCS= possibleClusterSystem[0];
|
|
}
|
|
// conflict case
|
|
else
|
|
{
|
|
// compute the hierarchy level of each cluster system, take the highest
|
|
CInstanceGroup *highest= NULL;
|
|
uint highestLevel= 0;
|
|
for(i=0;i<possibleClusterSystem.size();i++)
|
|
{
|
|
uint level= 0;
|
|
CInstanceGroup *ig= possibleClusterSystem[i];
|
|
while(ig)
|
|
{
|
|
ig= ig->getParentClusterSystem();
|
|
level++;
|
|
}
|
|
if(level>=highestLevel)
|
|
{
|
|
highestLevel= level;
|
|
highest= possibleClusterSystem[i];
|
|
}
|
|
}
|
|
|
|
// set the highest cluster system
|
|
resultCS= highest;
|
|
}
|
|
|
|
return resultCS;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::renderOcclusionTestMeshsWithCurrMaterial()
|
|
{
|
|
for(std::set<CTransform*>::iterator it = _Models.begin(); it != _Models.end(); ++it)
|
|
{
|
|
if ((*it)->isFlare())
|
|
{
|
|
CFlareModel *flare = NLMISC::safe_cast<CFlareModel *>(*it);
|
|
flare->renderOcclusionTestMesh(*RenderTrav.getDriver());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::renderOcclusionTestMeshs()
|
|
{
|
|
nlassert(RenderTrav.getDriver());
|
|
RenderTrav.getDriver()->setupViewport(RenderTrav.getViewport());
|
|
RenderTrav.getDriver()->activeVertexProgram(NULL);
|
|
IDriver::TPolygonMode oldPolygonMode = RenderTrav.getDriver()->getPolygonMode();
|
|
CMaterial m;
|
|
m.initUnlit();
|
|
m.setColor(CRGBA(255, 255, 255, 127));
|
|
m.setBlend(true);
|
|
m.setDstBlend(CMaterial::invsrcalpha);
|
|
m.setSrcBlend(CMaterial::srcalpha);
|
|
m.setZWrite(false);
|
|
RenderTrav.getDriver()->setupMaterial(m);
|
|
getDriver()->setPolygonMode(IDriver::Filled);
|
|
renderOcclusionTestMeshsWithCurrMaterial();
|
|
m.setColor(CRGBA::Black);
|
|
RenderTrav.getDriver()->setupMaterial(m);
|
|
getDriver()->setPolygonMode(IDriver::Line);
|
|
renderOcclusionTestMeshsWithCurrMaterial();
|
|
getDriver()->setPolygonMode(oldPolygonMode);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::updateWaterEnvMaps(TGlobalAnimationTime time)
|
|
{
|
|
IDriver *drv = getDriver();
|
|
nlassert(drv);
|
|
if (_WaterEnvMap)
|
|
{
|
|
_WaterEnvMap->update(time, *drv);
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CScene::addSSSModelRequest(const class CSSSModelRequest &req)
|
|
{
|
|
_SSSModelRequests.push_back(req);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CScene::flushSSSModelRequests()
|
|
{
|
|
for(uint i=0;i<_SSSModelRequests.size();i++)
|
|
{
|
|
_SSSModelRequests[i].execute();
|
|
}
|
|
_SSSModelRequests.clear();
|
|
}
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|