1570 lines
45 KiB
C++
1570 lines
45 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_group.h"
|
|
#include "nel/misc/stream.h"
|
|
#include "nel/misc/matrix.h"
|
|
#include "nel/3d/scene.h"
|
|
#include "nel/3d/transform_shape.h"
|
|
#include "nel/3d/mesh_instance.h"
|
|
#include "nel/3d/shape_bank.h"
|
|
#include "nel/3d/u_instance_group.h"
|
|
#include "nel/3d/vertex_buffer.h"
|
|
#include "nel/3d/index_buffer.h"
|
|
#include "nel/3d/text_context.h"
|
|
#include "nel/3d/water_model.h"
|
|
#include "nel/3d/water_shape.h"
|
|
#include "nel/misc/polygon.h"
|
|
#include "nel/misc/path.h"
|
|
|
|
|
|
using namespace NLMISC;
|
|
using namespace std;
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CInstance
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup::CInstance::CInstance ()
|
|
{
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
DontAddToScene = false;
|
|
AvoidStaticLightPreCompute= false;
|
|
StaticLightEnabled= false;
|
|
DontCastShadow= false;
|
|
LocalAmbientId= 0xFF;
|
|
DontCastShadowForInterior= false;
|
|
DontCastShadowForExterior= false;
|
|
Visible= true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::CInstance::serial (NLMISC::IStream& f)
|
|
{
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
/*
|
|
Version 7:
|
|
- Visible
|
|
Version 6:
|
|
- DontCastShadowForExterior
|
|
Version 5:
|
|
- DontCastShadowForInterior
|
|
Version 4:
|
|
- LocalAmbientId.
|
|
Version 3:
|
|
- StaticLight.
|
|
Version 2:
|
|
- gameDev data.
|
|
Version 1:
|
|
- Clusters
|
|
*/
|
|
// Serial a version number
|
|
sint version=f.serialVersion (7);
|
|
|
|
|
|
// Visible
|
|
if (version >= 7)
|
|
f.serial(Visible);
|
|
|
|
// DontCastShadowForExterior
|
|
if (version >= 6)
|
|
f.serial(DontCastShadowForExterior);
|
|
else
|
|
DontCastShadowForExterior= false;
|
|
|
|
// DontCastShadowForInterior
|
|
if (version >= 5)
|
|
f.serial(DontCastShadowForInterior);
|
|
else
|
|
DontCastShadowForInterior= false;
|
|
|
|
// Serial the LocalAmbientId.
|
|
if (version >= 4)
|
|
{
|
|
f.serial(LocalAmbientId);
|
|
}
|
|
else if(f.isReading())
|
|
{
|
|
LocalAmbientId= 0xFF;
|
|
}
|
|
|
|
// Serial the StaticLight
|
|
if (version >= 3)
|
|
{
|
|
f.serial (AvoidStaticLightPreCompute);
|
|
f.serial (DontCastShadow);
|
|
f.serial (StaticLightEnabled);
|
|
f.serial (SunContribution);
|
|
nlassert(CInstanceGroup::NumStaticLightPerInstance==2);
|
|
f.serial (Light[0]);
|
|
f.serial (Light[1]);
|
|
}
|
|
else if(f.isReading())
|
|
{
|
|
AvoidStaticLightPreCompute= false;
|
|
StaticLightEnabled= false;
|
|
DontCastShadow= false;
|
|
}
|
|
|
|
// Serial the gamedev data
|
|
if (version >= 2)
|
|
{
|
|
f.serial (InstanceName);
|
|
f.serial (DontAddToScene);
|
|
}
|
|
|
|
// Serial the clusters
|
|
if (version >= 1)
|
|
f.serialCont (Clusters);
|
|
|
|
// Serial the name
|
|
f.serial (Name);
|
|
|
|
// Serial the position vector
|
|
f.serial (Pos);
|
|
|
|
// Serial the rotation vector
|
|
f.serial (Rot);
|
|
|
|
// Serial the scale vector
|
|
f.serial (Scale);
|
|
|
|
// Serial the parent location in the vector (-1 if no parent)
|
|
f.serial (nParent);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CInstanceGroup
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ***************************************************************************
|
|
|
|
uint CInstanceGroup::getNumInstance () const
|
|
{
|
|
return (uint)_InstancesInfos.size();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const string& CInstanceGroup::getShapeName (uint instanceNb) const
|
|
{
|
|
// Return the name of the n-th instance
|
|
return _InstancesInfos[instanceNb].Name;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const string& CInstanceGroup::getInstanceName (uint instanceNb) const
|
|
{
|
|
// Return the name of the n-th instance
|
|
return _InstancesInfos[instanceNb].InstanceName;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const CVector& CInstanceGroup::getInstancePos (uint instanceNb) const
|
|
{
|
|
// Return the position vector of the n-th instance
|
|
return _InstancesInfos[instanceNb].Pos;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const CQuat& CInstanceGroup::getInstanceRot (uint instanceNb) const
|
|
{
|
|
// Return the rotation vector of the n-th instance
|
|
return _InstancesInfos[instanceNb].Rot;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
const CVector& CInstanceGroup::getInstanceScale (uint instanceNb) const
|
|
{
|
|
// Return the scale vector of the n-th instance
|
|
return _InstancesInfos[instanceNb].Scale;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CInstanceGroup::getInstanceMatrix(uint instanceNb,NLMISC::CMatrix &dest) const
|
|
{
|
|
dest.identity();
|
|
dest.translate(getInstancePos(instanceNb));
|
|
dest.rotate(getInstanceRot(instanceNb));
|
|
dest.scale(getInstanceScale(instanceNb));
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
sint32 CInstanceGroup::getInstanceParent (uint instanceNb) const
|
|
{
|
|
// Return the scale vector of the n-th instance
|
|
return _InstancesInfos[instanceNb].nParent;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
const CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb) const
|
|
{
|
|
return _InstancesInfos[instanceNb];
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup::CInstance &CInstanceGroup::getInstance(uint instanceNb)
|
|
{
|
|
return _InstancesInfos[instanceNb];
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CTransformShape *CInstanceGroup::getTransformShape(uint instanceNb) const
|
|
{
|
|
if(instanceNb>_Instances.size())
|
|
return NULL;
|
|
return _Instances[instanceNb];
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup::CInstanceGroup()
|
|
{
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
_IGSurfaceLight.setOwner(this);
|
|
_GlobalPos = CVector(0,0,0);
|
|
_Root = NULL;
|
|
_ClusterSystemForInstances = NULL;
|
|
_ParentClusterSystem = NULL;
|
|
_RealTimeSunContribution= true;
|
|
_AddToSceneState = StateNotAdded;
|
|
_TransformName = NULL;
|
|
_AddRemoveInstance = NULL;
|
|
_IGAddBeginCallback = NULL;
|
|
_UserIg= NULL;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup::~CInstanceGroup()
|
|
{
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array,
|
|
const std::vector<CCluster>& Clusters,
|
|
const std::vector<CPortal>& Portals,
|
|
const std::vector<CPointLightNamed> &pointLightList,
|
|
const CIGSurfaceLight::TRetrieverGridMap *retrieverGridMap,
|
|
float igSurfaceLightCellSize)
|
|
{
|
|
_GlobalPos = vGlobalPos;
|
|
// Copy the array
|
|
_InstancesInfos = array;
|
|
|
|
_Portals = Portals;
|
|
_ClusterInfos = Clusters;
|
|
|
|
// Link portals and clusters
|
|
uint32 i, j, k;
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
{
|
|
for (j = 0; j < _ClusterInfos.size(); ++j)
|
|
{
|
|
bool bPortalInCluster = true;
|
|
for (k = 0; k < _Portals[i]._Poly.size(); ++k)
|
|
if (!_ClusterInfos[j].isIn (_Portals[i]._Poly[k]) )
|
|
{
|
|
bPortalInCluster = false;
|
|
break;
|
|
}
|
|
if (bPortalInCluster)
|
|
{
|
|
_Portals[i].setCluster(&_ClusterInfos[j]);
|
|
_ClusterInfos[j].link (&_Portals[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create Meta Cluster if needed
|
|
/*
|
|
CCluster clusterTemp;
|
|
bool mustAdd = false;
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
if (_Portals[i].getNbCluster() == 1)
|
|
{
|
|
mustAdd = true;
|
|
break;
|
|
}
|
|
if (mustAdd)
|
|
{
|
|
CCluster clusterTemp;
|
|
_ClusterInfos.push_back(clusterTemp);
|
|
CCluster *pMetaCluster = &_ClusterInfos[_ClusterInfos.size()-1];
|
|
pMetaCluster->setMetaCluster();
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
if (_Portals[i].getNbCluster() == 1)
|
|
{
|
|
_Portals[i].setCluster(pMetaCluster);
|
|
pMetaCluster->link(&_Portals[i]);
|
|
}
|
|
}*/
|
|
|
|
|
|
// Build the list of light. NB: sort by LightGroupName the array.
|
|
std::vector<uint> plRemap;
|
|
buildPointLightList(pointLightList, plRemap);
|
|
|
|
// Build IgSurfaceLight
|
|
// clear
|
|
_IGSurfaceLight.clear();
|
|
if(retrieverGridMap)
|
|
{
|
|
//build
|
|
_IGSurfaceLight.build(*retrieverGridMap, igSurfaceLightCellSize, plRemap);
|
|
}
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::build (const CVector &vGlobalPos, const TInstanceArray& array,
|
|
const std::vector<CCluster>& Clusters,
|
|
const std::vector<CPortal>& Portals)
|
|
{
|
|
// empty pointLightList
|
|
std::vector<CPointLightNamed> pointLightList;
|
|
|
|
build(vGlobalPos, array, Clusters, Portals, pointLightList);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::retrieve (CVector &vGlobalPos, TInstanceArray& array,
|
|
std::vector<CCluster>& Clusters,
|
|
std::vector<CPortal>& Portals,
|
|
std::vector<CPointLightNamed> &pointLightList) const
|
|
{
|
|
// Just copy infos. NB: light information order have change but is still valid
|
|
vGlobalPos= _GlobalPos;
|
|
array= _InstancesInfos;
|
|
|
|
Portals= _Portals;
|
|
Clusters= _ClusterInfos;
|
|
// Must reset links to all portals and clusters.
|
|
uint i;
|
|
for(i=0; i<Portals.size(); i++)
|
|
Portals[i].resetClusterLinks();
|
|
for(i=0; i<Clusters.size(); i++)
|
|
Clusters[i].resetPortalLinks();
|
|
|
|
|
|
pointLightList= getPointLightList();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
void CInstanceGroup::serial (NLMISC::IStream& f)
|
|
{
|
|
/* ***********************************************
|
|
* WARNING: This Class/Method must be thread-safe (ctor/dtor/serial): no static access for instance
|
|
* It can be loaded/called through CAsyncFileManager for instance
|
|
* ***********************************************/
|
|
|
|
// Serial a header
|
|
f.serialCheck ((uint32)'TPRG');
|
|
|
|
/*
|
|
Version 5:
|
|
_ _RealTimeSunContribution
|
|
Version 4:
|
|
_ IGSurfaceLight
|
|
Version 3:
|
|
- PointLights
|
|
*/
|
|
// Serial a version number
|
|
sint version=f.serialVersion (5);
|
|
|
|
|
|
// _RealTimeSunContribution
|
|
if (version >= 5)
|
|
{
|
|
f.serial(_RealTimeSunContribution);
|
|
}
|
|
else if(f.isReading())
|
|
{
|
|
_RealTimeSunContribution= true;
|
|
}
|
|
|
|
|
|
// Serial the IGSurfaceLight
|
|
if (version >= 4)
|
|
{
|
|
f.serial(_IGSurfaceLight);
|
|
}
|
|
else if(f.isReading())
|
|
{
|
|
_IGSurfaceLight.clear();
|
|
}
|
|
|
|
|
|
// Serial the PointLights info
|
|
if (version >= 3)
|
|
{
|
|
f.serial(_PointLightArray);
|
|
}
|
|
else if(f.isReading())
|
|
{
|
|
_PointLightArray.clear();
|
|
}
|
|
|
|
|
|
if (version >= 2)
|
|
f.serial(_GlobalPos);
|
|
|
|
if (version >= 1)
|
|
{
|
|
f.serialCont (_ClusterInfos);
|
|
f.serialCont (_Portals);
|
|
// Links
|
|
if (f.isReading())
|
|
{
|
|
uint32 i, j;
|
|
for (i = 0; i < _ClusterInfos.size(); ++i)
|
|
{
|
|
uint32 nNbPortals;
|
|
f.serial (nNbPortals);
|
|
_ClusterInfos[i]._Portals.resize (nNbPortals);
|
|
// Recreate clusters to portals links
|
|
for (j = 0; j < nNbPortals; ++j)
|
|
{
|
|
sint32 nPortalNb;
|
|
f.serial (nPortalNb);
|
|
_ClusterInfos[i]._Portals[j] = &_Portals[nPortalNb];
|
|
_Portals[nPortalNb].setCluster (&_ClusterInfos[i]);
|
|
}
|
|
}
|
|
}
|
|
else // We are writing to the stream
|
|
{
|
|
uint32 i, j;
|
|
for (i = 0; i < _ClusterInfos.size(); ++i)
|
|
{
|
|
uint32 nNbPortals = (uint32)_ClusterInfos[i]._Portals.size();
|
|
f.serial (nNbPortals);
|
|
for (j = 0; j < nNbPortals; ++j)
|
|
{
|
|
sint32 nPortalNb = (sint32)(_ClusterInfos[i]._Portals[j] - &_Portals[0]);
|
|
f.serial (nPortalNb);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Serial the array
|
|
f.serialCont (_InstancesInfos);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::createRoot (CScene& scene)
|
|
{
|
|
_Root = (CTransform*)scene.createModel (TransformId);
|
|
_Root->setDontUnfreezeChildren (true);
|
|
setPos (CVector(0,0,0));
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setTransformNameCallback (ITransformName *pTN)
|
|
{
|
|
_TransformName = pTN;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setAddRemoveInstanceCallback(IAddRemoveInstance *callback)
|
|
{
|
|
_AddRemoveInstance = callback;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setIGAddBeginCallback(IIGAddBegin *callback)
|
|
{
|
|
_IGAddBeginCallback = callback;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInstanceGroup::addToScene (CScene& scene, IDriver *driver, uint selectedTexture)
|
|
{
|
|
// Init the scene lights
|
|
_PointLightArray.initAnimatedLightIndex (scene);
|
|
|
|
uint32 i, j;
|
|
|
|
// Test if portals are linked to their 2 clusters
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
if (_Portals[i]._Clusters[j] == NULL)
|
|
{
|
|
nlwarning("Portal %d (name:%s) is not linked to 2 clusters. Instance Group Not Added To Scene.", i, _Portals[i].getName().c_str());
|
|
}
|
|
}
|
|
|
|
_Instances.resize (_InstancesInfos.size(), NULL);
|
|
|
|
if (_IGAddBeginCallback)
|
|
_IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size());
|
|
|
|
// Creation and positionning of the new instance
|
|
|
|
vector<CInstance>::iterator it = _InstancesInfos.begin();
|
|
|
|
// Water surface may have a callback when they are created, and this callback need their position
|
|
// Their position isn't set right now however, so must call that callback later
|
|
IWaterSurfaceAddedCallback *oldCallback = scene.getWaterCallback();
|
|
scene.setWaterCallback(NULL);
|
|
for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
|
|
{
|
|
// Get the shape name
|
|
string shapeName;
|
|
getShapeName (i, shapeName);
|
|
if (!shapeName.empty ())
|
|
{
|
|
if (!_InstancesInfos[i].DontAddToScene)
|
|
{
|
|
// TMP FIX : some pacs_prim files where exported ...
|
|
if (nlstricmp(NLMISC::CFile::getExtension(shapeName), "pacs_prim") == 0)
|
|
{
|
|
nlwarning("Can't read %s (not a shape)", shapeName.c_str());
|
|
_Instances[i] = NULL;
|
|
}
|
|
else
|
|
{
|
|
_Instances[i] = scene.createInstance (shapeName);
|
|
}
|
|
if( _Instances[i] == NULL )
|
|
{
|
|
nlwarning("Not found '%s' file\n", shapeName.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
scene.setWaterCallback(oldCallback);
|
|
return addToSceneWhenAllShapesLoaded (scene, driver, selectedTexture);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
|
|
void CInstanceGroup::getShapeName (uint instanceIndex, std::string &shapeName) const
|
|
{
|
|
const CInstance &rInstanceInfo = _InstancesInfos[instanceIndex];
|
|
shapeName = rInstanceInfo.Name;
|
|
|
|
// If there is a callback added to this instance group then transform
|
|
// the name of the shape to load.
|
|
if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
|
|
{
|
|
shapeName = _TransformName->transformName (instanceIndex, rInstanceInfo.InstanceName, rInstanceInfo.Name);
|
|
}
|
|
|
|
toLower(shapeName);
|
|
if (!shapeName.empty() && shapeName.find('.') == std::string::npos)
|
|
shapeName += ".shape";
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Private method
|
|
bool CInstanceGroup::addToSceneWhenAllShapesLoaded (CScene& scene, IDriver *driver, uint selectedTexture)
|
|
{
|
|
uint32 i, j;
|
|
|
|
vector<CInstance>::iterator it = _InstancesInfos.begin();
|
|
for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
|
|
{
|
|
CInstance &rInstanceInfo = *it;
|
|
|
|
if (!rInstanceInfo.DontAddToScene)
|
|
{
|
|
if (_Instances[i])
|
|
{
|
|
_Instances[i]->setPos (rInstanceInfo.Pos);
|
|
_Instances[i]->setRotQuat (rInstanceInfo.Rot);
|
|
_Instances[i]->setScale (rInstanceInfo.Scale);
|
|
_Instances[i]->setPivot (CVector::Null);
|
|
if(rInstanceInfo.Visible)
|
|
_Instances[i]->show();
|
|
else
|
|
_Instances[i]->hide();
|
|
|
|
if (scene.getWaterCallback())
|
|
{
|
|
CWaterModel *wm = dynamic_cast<CWaterModel *>(_Instances[i]);
|
|
if (wm)
|
|
{
|
|
const CWaterShape *ws = safe_cast<const CWaterShape *>((const IShape *) wm->Shape);
|
|
scene.getWaterCallback()->waterSurfaceAdded(ws->getShape(), wm->getMatrix(), ws->isSplashEnabled(), ws->getUseSceneWaterEnvMap(0) || ws->getUseSceneWaterEnvMap(1));
|
|
}
|
|
}
|
|
// Static Light Setup
|
|
if( rInstanceInfo.StaticLightEnabled )
|
|
{
|
|
// Count lights.
|
|
uint numPointLights;
|
|
for(numPointLights= 0; numPointLights<CInstanceGroup::NumStaticLightPerInstance; numPointLights++)
|
|
{
|
|
if(rInstanceInfo.Light[numPointLights]==0xFF)
|
|
break;
|
|
}
|
|
// Max allowed.
|
|
numPointLights= min(numPointLights, (uint)NL3D_MAX_LIGHT_CONTRIBUTION);
|
|
|
|
// Get pl ptrs.
|
|
CPointLight *pls[CInstanceGroup::NumStaticLightPerInstance];
|
|
for(uint j=0; j<numPointLights;j++)
|
|
{
|
|
uint plId= rInstanceInfo.Light[j];
|
|
pls[j]= (CPointLight*)(&_PointLightArray.getPointLights()[plId]);
|
|
}
|
|
|
|
// get frozenAmbientlight.
|
|
CPointLight *frozenAmbientlight;
|
|
if(rInstanceInfo.LocalAmbientId == 0xFF)
|
|
// must take the sun one.
|
|
frozenAmbientlight= NULL;
|
|
else
|
|
// ok, take the local ambient one.
|
|
frozenAmbientlight= (CPointLight*)(&_PointLightArray.getPointLights()[rInstanceInfo.LocalAmbientId]);
|
|
|
|
// Setup the instance.
|
|
_Instances[i]->freezeStaticLightSetup(pls, numPointLights, rInstanceInfo.SunContribution, frozenAmbientlight);
|
|
}
|
|
|
|
// Driver not NULL ?
|
|
if (driver)
|
|
{
|
|
// Flush shape's texture with this driver
|
|
_Instances[i]->Shape->flushTextures (*driver, selectedTexture);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_Instances[i] = NULL;
|
|
}
|
|
}
|
|
|
|
// Setup the hierarchy
|
|
// We just have to set the traversal HRC (Hierarchy)
|
|
if (_Root == NULL)
|
|
{
|
|
createRoot (scene);
|
|
}
|
|
it = _InstancesInfos.begin();
|
|
for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
|
|
if (!_InstancesInfos[i].DontAddToScene && _Instances[i] != NULL)
|
|
{
|
|
CInstance &rInstanceInfo = *it;
|
|
if( rInstanceInfo.nParent != -1 ) // Is the instance get a parent
|
|
_Instances[rInstanceInfo.nParent]->hrcLinkSon( _Instances[i] );
|
|
else
|
|
_Root->hrcLinkSon( _Instances[i] );
|
|
}
|
|
// Attach the root of the instance group to the root of the hierarchy traversal
|
|
scene.getRoot()->hrcLinkSon( _Root );
|
|
|
|
// Cluster / Portals
|
|
// -----------------
|
|
|
|
CClipTrav *pClipTrav = &scene.getClipTrav();
|
|
_ClipTrav = pClipTrav;
|
|
|
|
// Create the MOT links (create the physical clusters)
|
|
_ClusterInstances.resize (_ClusterInfos.size());
|
|
for (i = 0; i < _ClusterInstances.size(); ++i)
|
|
{
|
|
_ClusterInstances[i] = (CCluster*)scene.createModel (ClusterId);
|
|
_ClusterInstances[i]->Group = this;
|
|
_ClusterInstances[i]->_Portals = _ClusterInfos[i]._Portals;
|
|
_ClusterInstances[i]->_LocalVolume = _ClusterInfos[i]._LocalVolume;
|
|
_ClusterInstances[i]->_LocalBBox = _ClusterInfos[i]._LocalBBox;
|
|
_ClusterInstances[i]->_Volume = _ClusterInfos[i]._Volume;
|
|
_ClusterInstances[i]->_BBox = _ClusterInfos[i]._BBox;
|
|
_ClusterInstances[i]->FatherVisible = _ClusterInfos[i].FatherVisible;
|
|
_ClusterInstances[i]->VisibleFromFather = _ClusterInfos[i].VisibleFromFather;
|
|
_ClusterInstances[i]->FatherAudible = _ClusterInfos[i].FatherAudible;
|
|
_ClusterInstances[i]->AudibleFromFather = _ClusterInfos[i].AudibleFromFather;
|
|
_ClusterInstances[i]->Name = _ClusterInfos[i].Name;
|
|
_ClusterInstances[i]->setSoundGroup(_ClusterInfos[i].getSoundGroup());
|
|
_ClusterInstances[i]->setEnvironmentFx(_ClusterInfos[i].getEnvironmentFx());
|
|
pClipTrav->registerCluster (_ClusterInstances[i]);
|
|
_ClusterInstances[i]->clipUnlinkFromAll();
|
|
}
|
|
|
|
// Relink portals with newly created clusters
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
for (j = 0; j < 2; ++j)
|
|
{
|
|
if (_Portals[i]._Clusters[j])
|
|
{
|
|
sint32 nClusterNb;
|
|
nClusterNb = (sint32)(_Portals[i]._Clusters[j] - &_ClusterInfos[0]);
|
|
_Portals[i]._Clusters[j] = _ClusterInstances[nClusterNb];
|
|
}
|
|
}
|
|
|
|
// Link shapes to clusters
|
|
for (i = 0; i < _Instances.size(); ++i)
|
|
if (_Instances[i] != NULL && !_InstancesInfos[i].DontAddToScene)
|
|
{
|
|
if (_InstancesInfos[i].Clusters.size() > 0)
|
|
{
|
|
_Instances[i]->clipUnlinkFromAll();
|
|
for (j = 0; j < _InstancesInfos[i].Clusters.size(); ++j)
|
|
_ClusterInstances[_InstancesInfos[i].Clusters[j]]->clipAddChild( _Instances[i] );
|
|
// For the first time we have to set all the instances to NOT move (and not be rebinded)
|
|
_Instances[i]->freeze();
|
|
_Instances[i]->setClusterSystem (this);
|
|
}
|
|
else
|
|
{
|
|
// These instances are not attached to a cluster at this level so we cannot freeze them
|
|
// Moreover we must set their clustersystem they will be tested against
|
|
_Instances[i]->setClusterSystem (_ClusterSystemForInstances);
|
|
}
|
|
}
|
|
_Root->freeze();
|
|
|
|
// HRC OBS like
|
|
for (i = 0; i < _ClusterInstances.size(); ++i)
|
|
{
|
|
_ClusterInstances[i]->setWorldMatrix (_Root->getMatrix());
|
|
|
|
for (j = 0; j < _ClusterInstances[i]->getNbPortals(); ++j)
|
|
{
|
|
CPortal *pPortal = _ClusterInstances[i]->getPortal(j);
|
|
pPortal->setWorldMatrix (_Root->getMatrix());
|
|
}
|
|
|
|
// Re affect the cluster to the accelerator if not the root
|
|
if (!_ClusterInstances[i]->isRoot())
|
|
{
|
|
_ClipTrav->unregisterCluster(_ClusterInstances[i]);
|
|
_ClipTrav->registerCluster (_ClusterInstances[i]);
|
|
}
|
|
}
|
|
|
|
|
|
// Link the instance group to the parent
|
|
linkToParent (scene.getGlobalInstanceGroup());
|
|
|
|
// Attach the clusters to the root of the instance group
|
|
for (i = 0; i < _ClusterInstances.size(); ++i)
|
|
_Root->hrcLinkSon( _ClusterInstances[i] );
|
|
|
|
|
|
// Default: freezeHRC all instances.
|
|
freezeHRC();
|
|
|
|
|
|
// Register the instanceGroup for light animation
|
|
// -----------------
|
|
// If some PointLight to animate
|
|
if(_PointLightArray.getPointLights().size() > 0)
|
|
scene.addInstanceGroupForLightAnimation(this);
|
|
|
|
_AddToSceneState = StateAdded;
|
|
|
|
if (_AddRemoveInstance)
|
|
_AddRemoveInstance->instanceGroupAdded();
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInstanceGroup::addToSceneAsync (CScene& scene, IDriver *driver, uint selectedTexture)
|
|
{
|
|
// Init the scene lights
|
|
_PointLightArray.initAnimatedLightIndex (scene);
|
|
|
|
uint32 i;
|
|
|
|
_AddToSceneState = StateAdding;
|
|
_AddToSceneTempScene = &scene;
|
|
_AddToSceneTempDriver = driver;
|
|
_AddToSceneTempSelectTexture = selectedTexture;
|
|
|
|
_Instances.resize (_InstancesInfos.size(), NULL);
|
|
|
|
if (_IGAddBeginCallback)
|
|
_IGAddBeginCallback->startAddingIG((uint)_InstancesInfos.size());
|
|
|
|
// Creation and positionning of the new instance
|
|
|
|
vector<CInstance>::iterator it = _InstancesInfos.begin();
|
|
set<string> allShapesToLoad;
|
|
_AddToSceneSignal = false;
|
|
bool loadAsyncStarted = false;
|
|
for (i = 0; i < _InstancesInfos.size(); ++i, ++it)
|
|
{
|
|
CInstance &rInstanceInfo = *it;
|
|
if (!rInstanceInfo.DontAddToScene)
|
|
{
|
|
string shapeName = rInstanceInfo.Name;
|
|
if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
|
|
{
|
|
shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name);
|
|
}
|
|
|
|
toLower(shapeName);
|
|
|
|
if (!shapeName.empty() && shapeName.find('.') == std::string::npos)
|
|
shapeName += ".shape";
|
|
|
|
|
|
if (allShapesToLoad.find(shapeName) == allShapesToLoad.end())
|
|
{
|
|
allShapesToLoad.insert (shapeName);
|
|
if (scene.getShapeBank()->getPresentState(shapeName) != CShapeBank::Present)
|
|
{
|
|
// Load it from file asynchronously
|
|
scene.getShapeBank()->loadAsync (shapeName, scene.getDriver(), rInstanceInfo.Pos, &_AddToSceneSignal, selectedTexture);
|
|
loadAsyncStarted = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!loadAsyncStarted)
|
|
_AddToSceneSignal = true;
|
|
else
|
|
_AddToSceneSignal = false;
|
|
//CAsyncFileManager::getInstance().signal (&_AddToSceneSignal);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::stopAddToSceneAsync ()
|
|
{
|
|
if (_AddToSceneState != StateAdding)
|
|
return;
|
|
vector<CInstance>::iterator it = _InstancesInfos.begin();
|
|
CAsyncFileManager::getInstance().cancelSignal (&_AddToSceneSignal);
|
|
for (uint32 i = 0; i < _InstancesInfos.size(); ++i, ++it)
|
|
{
|
|
CInstance &rInstanceInfo = *it;
|
|
if (!rInstanceInfo.DontAddToScene)
|
|
{
|
|
string shapeName;
|
|
|
|
|
|
bool getShapeName = true;
|
|
|
|
if (_TransformName != NULL && !rInstanceInfo.InstanceName.empty())
|
|
{
|
|
shapeName = _TransformName->transformName (i, rInstanceInfo.InstanceName, rInstanceInfo.Name);
|
|
if (shapeName != rInstanceInfo.Name)
|
|
getShapeName = false;
|
|
}
|
|
|
|
|
|
if (getShapeName)
|
|
{
|
|
if (rInstanceInfo.Name.find('.') == std::string::npos)
|
|
shapeName = rInstanceInfo.Name + ".shape";
|
|
else // extension has already been added
|
|
shapeName = rInstanceInfo.Name;
|
|
}
|
|
|
|
toLower(shapeName);
|
|
_AddToSceneTempScene->getShapeBank()->cancelLoadAsync (shapeName);
|
|
}
|
|
}
|
|
_AddToSceneState = StateNotAdded;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CInstanceGroup::TState CInstanceGroup::getAddToSceneState ()
|
|
{
|
|
// If we are adding but we have finished loading shapes (all shapes are here)
|
|
if (_AddToSceneState == StateAdding)
|
|
{
|
|
if (_AddToSceneSignal)
|
|
{
|
|
addToScene (*_AddToSceneTempScene, _AddToSceneTempDriver, _AddToSceneTempSelectTexture);
|
|
}
|
|
}
|
|
return _AddToSceneState;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// Search in the hierarchy of ig the most low level (child) ig that contains the clusters that
|
|
// are flagged to be visible from father or which father is visible
|
|
bool CInstanceGroup::linkToParent (CInstanceGroup *pFather)
|
|
{
|
|
uint32 i, j;
|
|
bool ret;
|
|
/*
|
|
for (i = 0; i < pFather->_ClusterInstances.size(); ++i)
|
|
{
|
|
for(j = 0; j < pFather->_ClusterInstances[i]->Children.size(); ++j)
|
|
{
|
|
if (linkToParent(pFather->_ClusterInstances[i]->Children[j]->Group))
|
|
return true;
|
|
}
|
|
}
|
|
*/
|
|
ret = false;
|
|
if (this != pFather)
|
|
{
|
|
for (j = 0; j < this->_ClusterInstances.size(); ++j)
|
|
{
|
|
if ((this->_ClusterInstances[j]->FatherVisible) ||
|
|
(this->_ClusterInstances[j]->VisibleFromFather))
|
|
{
|
|
for (i = 0; i < pFather->_ClusterInstances .size(); ++i)
|
|
{
|
|
// If my cluster j is in the cluster i of the father
|
|
if (pFather->_ClusterInstances[i]->isIn(this->_ClusterInstances[j]->getBBox()))
|
|
{
|
|
if (this->_ClusterInstances[j]->Father != pFather->_ClusterInstances[i]) // and not already son of the father cluster ?
|
|
{
|
|
// unlink from parent
|
|
this->_ClusterInstances[j]->unlinkFromParent();
|
|
|
|
// relink to the new father found
|
|
pFather->_ClusterInstances[i]->Children.push_back(this->_ClusterInstances[j]);
|
|
this->_ClusterInstances[j]->Father = pFather->_ClusterInstances[i];
|
|
}
|
|
ret = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// store new parent
|
|
if(ret)
|
|
_ParentClusterSystem= pFather;
|
|
|
|
return ret;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInstanceGroup::removeFromScene (CScene& scene)
|
|
{
|
|
uint32 i, j, k;
|
|
|
|
// Remove shapes
|
|
for (i = 0; i < _Instances.size(); ++i)
|
|
{
|
|
CTransformShape *pTShape = _Instances[i];
|
|
if(pTShape)
|
|
{
|
|
// For security, unfreeze any StaticLightSetup setuped.
|
|
pTShape->unfreezeStaticLightSetup();
|
|
// delete the instance
|
|
scene.deleteInstance (pTShape);
|
|
_Instances[i] = NULL;
|
|
}
|
|
}
|
|
|
|
// Relink portals with old clusters
|
|
for (i = 0; i < _Portals.size(); ++i)
|
|
for (k = 0; k < 2; ++k)
|
|
{
|
|
if (_Portals[i]._Clusters[k])
|
|
{
|
|
for (j = 0; j < _ClusterInstances.size(); ++j)
|
|
if( _Portals[i]._Clusters[k] == _ClusterInstances[j] )
|
|
break;
|
|
|
|
nlassert (j!=_ClusterInstances.size());
|
|
_Portals[i]._Clusters[k] = &_ClusterInfos[j];
|
|
}
|
|
}
|
|
|
|
// Remove clusters
|
|
CClipTrav *pClipTrav = &scene.getClipTrav();
|
|
for (i = 0; i < _ClusterInstances.size(); ++i)
|
|
{
|
|
pClipTrav->unregisterCluster (_ClusterInstances[i]);
|
|
scene.deleteModel (_ClusterInstances[i]);
|
|
}
|
|
|
|
scene.deleteModel (_Root);
|
|
_Root = NULL;
|
|
|
|
|
|
// UnRegister the instanceGroup for light animation
|
|
// -----------------
|
|
// If some PointLight to animate
|
|
if(_PointLightArray.getPointLights().size() > 0)
|
|
scene.removeInstanceGroupForLightAnimation(this);
|
|
|
|
if (_AddRemoveInstance)
|
|
_AddRemoveInstance->instanceGroupRemoved();
|
|
return true;
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::getLights( set<string> &LightNames )
|
|
{
|
|
LightNames.clear();
|
|
for( uint32 i = 0; i < _Instances.size(); ++i )
|
|
{
|
|
CMeshInstance *pMI = dynamic_cast<CMeshInstance*>(_Instances[i]);
|
|
if( pMI != NULL )
|
|
{
|
|
uint32 nNbLM = pMI->getNbLightMap();
|
|
for( uint32 j = 0; j < nNbLM; ++j )
|
|
{
|
|
string sTmp;
|
|
pMI->getLightMapName( j, sTmp );
|
|
set<string>::iterator itSet = LightNames.find(sTmp);
|
|
if( itSet == LightNames.end() )
|
|
LightNames.insert( sTmp );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::getBlendShapes( set<string> &BlendShapeNames )
|
|
{
|
|
BlendShapeNames.clear();
|
|
for( uint32 i = 0; i < _Instances.size(); ++i )
|
|
{
|
|
CMeshBaseInstance *pMBI = dynamic_cast<CMeshBaseInstance*>(_Instances[i]);
|
|
if (pMBI != NULL)
|
|
{
|
|
uint32 nNbBS = pMBI->getNbBlendShape();
|
|
for( uint32 j = 0; j < nNbBS; ++j )
|
|
{
|
|
string sTmp;
|
|
pMBI->getBlendShapeName( j, sTmp );
|
|
set<string>::iterator itSet = BlendShapeNames.find(sTmp);
|
|
if( itSet == BlendShapeNames.end() )
|
|
BlendShapeNames.insert( sTmp );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setBlendShapeFactor( const string &BlendShapeName, float rFactor )
|
|
{
|
|
for( uint32 i = 0; i < _Instances.size(); ++i )
|
|
{
|
|
CMeshBaseInstance *pMI = dynamic_cast<CMeshBaseInstance*>(_Instances[i]);
|
|
if( pMI != NULL )
|
|
{
|
|
pMI->setBlendShapeFactor( BlendShapeName, rFactor );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::addCluster(CCluster *pCluster)
|
|
{
|
|
_ClusterInstances.push_back(pCluster);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setClusterSystemForInstances(CInstanceGroup *pIG)
|
|
{
|
|
_ClusterSystemForInstances = pIG;
|
|
for (uint32 i = 0; i < _Instances.size(); ++i)
|
|
if (_Instances[i] && _InstancesInfos[i].Clusters.size() == 0)
|
|
_Instances[i]->setClusterSystem (_ClusterSystemForInstances);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::getDynamicPortals (std::vector<std::string> &names)
|
|
{
|
|
for (uint32 i = 0; i < _Portals.size(); ++i)
|
|
if (_Portals[i].getName() != "")
|
|
names.push_back (_Portals[i].getName());
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setDynamicPortal (std::string& name, bool opened)
|
|
{
|
|
for (uint32 i = 0; i < _Portals.size(); ++i)
|
|
if (_Portals[i].getName() == name)
|
|
_Portals[i].open (opened);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
bool CInstanceGroup::getDynamicPortal (std::string& name)
|
|
{
|
|
for (uint32 i = 0; i < _Portals.size(); ++i)
|
|
if (_Portals[i].getName() == name)
|
|
return _Portals[i].isOpened ();
|
|
return false;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setPos (const CVector &pos)
|
|
{
|
|
if (_Root != NULL)
|
|
/// \todo Make this work (precision): _Root->setPos (_GlobalPos+pos);
|
|
_Root->setPos (pos);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setRotQuat (const CQuat &quat)
|
|
{
|
|
if (_Root != NULL)
|
|
_Root->setRotQuat (quat);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CVector CInstanceGroup::getPos ()
|
|
{
|
|
if (_Root != NULL)
|
|
return _Root->getPos ();
|
|
else
|
|
return CVector(0.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
// ***************************************************************************
|
|
CQuat CInstanceGroup::getRotQuat ()
|
|
{
|
|
if (_Root != NULL)
|
|
return _Root->getRotQuat ();
|
|
else
|
|
return CQuat();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::linkRoot (CScene &/* scene */, CTransform *father)
|
|
{
|
|
if(_Root)
|
|
{
|
|
father->hrcLinkSon( _Root );
|
|
}
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::freezeHRC()
|
|
{
|
|
// For all instances.
|
|
for (uint i=0; i < _Instances.size(); i++)
|
|
{
|
|
if(_Instances[i])
|
|
_Instances[i]->freezeHRC();
|
|
}
|
|
// and for root.
|
|
_Root->freezeHRC();
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::unfreezeHRC()
|
|
{
|
|
// For all instances.
|
|
for (uint i=0; i < _Instances.size(); i++)
|
|
{
|
|
if(_Instances[i])
|
|
_Instances[i]->unfreezeHRC();
|
|
}
|
|
// and for root.
|
|
_Root->unfreezeHRC();
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::buildPointLightList(const std::vector<CPointLightNamed> &pointLightList,
|
|
std::vector<uint> &plRemap)
|
|
{
|
|
// build.
|
|
_PointLightArray.build(pointLightList, plRemap);
|
|
|
|
// remap Instance precalc lighted.
|
|
for(uint i=0; i<_InstancesInfos.size(); i++)
|
|
{
|
|
CInstance &inst= _InstancesInfos[i];
|
|
// If the instance has no precomputed lighting, skip
|
|
if(!inst.StaticLightEnabled)
|
|
continue;
|
|
|
|
// remap pointlights
|
|
for(uint l=0; l<CInstanceGroup::NumStaticLightPerInstance; l++)
|
|
{
|
|
// If NULL light, break and continue to next instance
|
|
if(inst.Light[l]== 0xFF)
|
|
break;
|
|
else
|
|
{
|
|
// Check good index.
|
|
nlassert(inst.Light[l] < _PointLightArray.getPointLights().size());
|
|
// Remap index, because of light sorting.
|
|
inst.Light[l]= uint8(plRemap[inst.Light[l]]);
|
|
}
|
|
}
|
|
|
|
// remap ambient light
|
|
if(inst.LocalAmbientId!=0xFF)
|
|
{
|
|
nlassert(inst.LocalAmbientId < _PointLightArray.getPointLights().size());
|
|
inst.LocalAmbientId= uint8(plRemap[inst.LocalAmbientId]);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::setPointLightFactor(const CScene &scene)
|
|
{
|
|
_PointLightArray.setPointLightFactor(scene);
|
|
}
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::enableRealTimeSunContribution(bool enable)
|
|
{
|
|
_RealTimeSunContribution= enable;
|
|
}
|
|
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
// ***************************************************************************
|
|
|
|
|
|
// ***************************************************************************
|
|
void CInstanceGroup::displayDebugClusters(IDriver *drv, class CTextContext *txtCtx)
|
|
{
|
|
uint opacity= 50;
|
|
CRGBA colorCluster(255, 128, 255, uint8(opacity));
|
|
// portals are drawn twice
|
|
CRGBA colorPortal(128, 255, 128, uint8(opacity/2));
|
|
|
|
CMaterial clusterMat;
|
|
CMaterial portalMat;
|
|
CMaterial lineMat;
|
|
clusterMat.initUnlit();
|
|
clusterMat.setBlend(true);
|
|
clusterMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
|
|
clusterMat.setZWrite(false);
|
|
clusterMat.setDoubleSided(true);
|
|
clusterMat.setColor(colorCluster);
|
|
portalMat.initUnlit();
|
|
portalMat.setBlend(true);
|
|
portalMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
|
|
portalMat.setZWrite(false);
|
|
portalMat.setDoubleSided(true);
|
|
portalMat.setColor(colorPortal);
|
|
lineMat.initUnlit();
|
|
lineMat.setBlend(true);
|
|
lineMat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
|
|
lineMat.setZWrite(false);
|
|
lineMat.setDoubleSided(true);
|
|
lineMat.setColor(CRGBA(0,0,0,uint8(opacity)));
|
|
|
|
|
|
// The geometry for each cluster
|
|
CVertexBuffer vb;
|
|
// too big cluster won't be rendered
|
|
const uint maxVertices= 10000;
|
|
vb.setVertexFormat(CVertexBuffer::PositionFlag);
|
|
vb.setNumVertices(maxVertices);
|
|
CIndexBuffer clusterTriangles;
|
|
CIndexBuffer clusterLines;
|
|
CIndexBuffer portalTriangles;
|
|
CIndexBuffer portalLines;
|
|
//
|
|
clusterTriangles.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
|
|
clusterLines.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
|
|
portalTriangles.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
|
|
portalLines.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
|
|
//
|
|
clusterTriangles.setNumIndexes(maxVertices*3);
|
|
clusterLines.setNumIndexes(maxVertices*2);
|
|
portalTriangles.setNumIndexes(maxVertices*3);
|
|
portalLines.setNumIndexes(maxVertices*2);
|
|
|
|
// setup identity matrix
|
|
drv->setupModelMatrix(CMatrix::Identity);
|
|
|
|
// For all clusters
|
|
uint i;
|
|
for(i=0;i<_ClusterInstances.size();i++)
|
|
{
|
|
CCluster *cluster= _ClusterInstances[i];
|
|
if(cluster)
|
|
{
|
|
uint numTotalVertices= 0;
|
|
|
|
// **** Build a set of polys representing the volume (slow but debug!)
|
|
static std::vector<CPolygon> polygons;
|
|
polygons.clear();
|
|
polygons.resize(cluster->_Volume.size());
|
|
// for each plane, build the associated polygon
|
|
uint j;
|
|
for(j=0;j<polygons.size();j++)
|
|
{
|
|
// Start with a big quad centered on bbox center
|
|
CPlane p= cluster->_Volume[j];
|
|
p.normalize();
|
|
CVector quadCenter= p.project(cluster->_BBox.getCenter());
|
|
|
|
// choose a basis on this plane
|
|
CMatrix mat;
|
|
mat.setArbitraryRotK(p.getNormal());
|
|
mat.setPos(quadCenter);
|
|
|
|
// Build the initial Big quad
|
|
CPolygon &poly= polygons[j];
|
|
poly.Vertices.resize(4);
|
|
float s= 10 * cluster->_BBox.getRadius();
|
|
poly.Vertices[0]= mat * CVector(-s,-s,0);
|
|
poly.Vertices[1]= mat * CVector(s,-s,0);
|
|
poly.Vertices[2]= mat * CVector(s,s,0);
|
|
poly.Vertices[3]= mat * CVector(-s,s,0);
|
|
|
|
// clip this poly against all the other (ie not me) planes
|
|
// This make this algo O(N2) but this is for debug....
|
|
for(uint k=0;k<cluster->_Volume.size();k++)
|
|
{
|
|
if(j!=k)
|
|
{
|
|
poly.clip(&cluster->_Volume[k], 1);
|
|
}
|
|
}
|
|
|
|
// count the number of vertices / triangles / lines to add
|
|
if(poly.Vertices.size()>=3)
|
|
{
|
|
numTotalVertices+= (uint)poly.Vertices.size();
|
|
}
|
|
}
|
|
|
|
// **** count the number of portals vertices
|
|
for(j=0;j<cluster->_Portals.size();j++)
|
|
{
|
|
numTotalVertices+= (uint)cluster->_Portals[j]->_Poly.size();
|
|
}
|
|
|
|
// **** Draw those cluster polygons, and portals
|
|
// too big clusters won't be rendered
|
|
if(numTotalVertices<=maxVertices)
|
|
{
|
|
uint iVert= 0;
|
|
uint j;
|
|
|
|
// build the cluster geometry
|
|
clusterTriangles.setNumIndexes(maxVertices*3);
|
|
clusterLines.setNumIndexes(maxVertices*2);
|
|
|
|
// Locks
|
|
CVertexBufferReadWrite vba;
|
|
vb.lock (vba);
|
|
CIndexBufferReadWrite ibaCT;
|
|
clusterTriangles.lock (ibaCT);
|
|
CIndexBufferReadWrite ibaCL;
|
|
clusterLines.lock (ibaCL);
|
|
|
|
uint numTriIndexes = 0;
|
|
uint numLineIndexes = 0;
|
|
|
|
for(j=0;j<polygons.size();j++)
|
|
{
|
|
CPolygon &poly= polygons[j];
|
|
if(poly.Vertices.size()>=3)
|
|
{
|
|
uint k;
|
|
// add the vertices
|
|
for(k=0;k<poly.Vertices.size();k++)
|
|
vba.setVertexCoord(iVert+k, poly.Vertices[k]);
|
|
|
|
// add the triangles
|
|
for(k=0;k<poly.Vertices.size()-2;k++)
|
|
{
|
|
if (numTriIndexes<clusterTriangles.capacity())
|
|
{
|
|
ibaCT.setTri(numTriIndexes, iVert+0, iVert+k+1, iVert+k+2);
|
|
numTriIndexes += 3;
|
|
}
|
|
}
|
|
|
|
// add the lines
|
|
for(k=0;k<poly.Vertices.size();k++)
|
|
{
|
|
if (numLineIndexes<clusterLines.capacity())
|
|
{
|
|
ibaCL.setLine(numLineIndexes, iVert+k, iVert+ ((k+1)%poly.Vertices.size()) );
|
|
numLineIndexes += 2;
|
|
}
|
|
}
|
|
|
|
iVert+= (uint)poly.Vertices.size();
|
|
}
|
|
}
|
|
|
|
// Unlocks
|
|
ibaCT.unlock ();
|
|
ibaCL.unlock ();
|
|
clusterTriangles.setNumIndexes(numTriIndexes);
|
|
clusterLines.setNumIndexes(numLineIndexes);
|
|
|
|
// build the portal geometry
|
|
portalTriangles.setNumIndexes(maxVertices*3);
|
|
portalLines.setNumIndexes(maxVertices*2);
|
|
|
|
// Locks
|
|
CIndexBufferReadWrite ibaPT;
|
|
portalTriangles.lock (ibaPT);
|
|
CIndexBufferReadWrite ibaPL;
|
|
portalLines.lock (ibaPL);
|
|
|
|
numTriIndexes = 0;
|
|
numLineIndexes = 0;
|
|
|
|
for(j=0;j<cluster->_Portals.size();j++)
|
|
{
|
|
std::vector<CVector> &portalVerts= cluster->_Portals[j]->_Poly;
|
|
if(portalVerts.size()>=3)
|
|
{
|
|
uint k;
|
|
// add the vertices
|
|
for(k=0;k<portalVerts.size();k++)
|
|
vba.setVertexCoord(iVert+k, portalVerts[k]);
|
|
|
|
// add the triangles
|
|
for(k=0;k<portalVerts.size()-2;k++)
|
|
{
|
|
if (numTriIndexes<clusterTriangles.capacity())
|
|
{
|
|
ibaPT.setTri(numTriIndexes, iVert+0, iVert+k+1, iVert+k+2);
|
|
numTriIndexes += 3;
|
|
}
|
|
}
|
|
|
|
// add the lines
|
|
for(k=0;k<portalVerts.size();k++)
|
|
{
|
|
if (numTriIndexes<clusterTriangles.capacity())
|
|
{
|
|
ibaPL.setLine(numLineIndexes, iVert+k, iVert+ ((k+1)%portalVerts.size()) );
|
|
numLineIndexes += 2;
|
|
}
|
|
}
|
|
|
|
iVert+= (uint)portalVerts.size();
|
|
}
|
|
}
|
|
|
|
// Unlock
|
|
ibaPT.unlock ();
|
|
ibaPL.unlock ();
|
|
portalTriangles.setNumIndexes(numTriIndexes);
|
|
portalLines.setNumIndexes(numLineIndexes);
|
|
vba.unlock ();
|
|
|
|
// render 2 pass with or without ZBuffer (for clearness)
|
|
for(uint pass=0;pass<2;pass++)
|
|
{
|
|
if(pass==0)
|
|
{
|
|
clusterMat.setZFunc(CMaterial::always);
|
|
portalMat.setZFunc(CMaterial::always);
|
|
lineMat.setZFunc(CMaterial::always);
|
|
}
|
|
else
|
|
{
|
|
clusterMat.setZFunc(CMaterial::lessequal);
|
|
portalMat.setZFunc(CMaterial::lessequal);
|
|
lineMat.setZFunc(CMaterial::lessequal);
|
|
}
|
|
|
|
drv->activeVertexBuffer(vb);
|
|
drv->activeIndexBuffer(clusterTriangles);
|
|
drv->renderTriangles (clusterMat, 0, clusterTriangles.getNumIndexes()/3);
|
|
drv->activeIndexBuffer(clusterLines);
|
|
drv->renderLines (lineMat, 0, clusterLines.getNumIndexes()/2);
|
|
drv->activeIndexBuffer(portalTriangles);
|
|
drv->renderTriangles (portalMat, 0, portalTriangles.getNumIndexes()/3);
|
|
drv->activeIndexBuffer(portalLines);
|
|
drv->renderLines (lineMat, 0, portalLines.getNumIndexes()/2);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// **** For all clusters, Draw the cluster name at center of the cluster
|
|
if(txtCtx)
|
|
{
|
|
CComputedString computedStr;
|
|
|
|
// bkup fontSize
|
|
uint bkFontSize;
|
|
CMatrix fontMatrix;
|
|
bkFontSize= txtCtx->getFontSize();
|
|
// to be readable
|
|
txtCtx->setFontSize(24);
|
|
|
|
// the font matrix
|
|
fontMatrix.setRot(drv->getViewMatrix().inverted());
|
|
fontMatrix.normalize(CMatrix::YZX);
|
|
fontMatrix.scale(10);
|
|
|
|
// parse all clusters
|
|
for(i=0;i<_ClusterInstances.size();i++)
|
|
{
|
|
CCluster *cluster= _ClusterInstances[i];
|
|
if(cluster)
|
|
{
|
|
fontMatrix.setPos(cluster->_BBox.getCenter());
|
|
txtCtx->computeString(cluster->Name, computedStr);
|
|
computedStr.render3D(*drv, fontMatrix);
|
|
}
|
|
}
|
|
|
|
// restore fontsize
|
|
txtCtx->setFontSize(bkFontSize);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
} // NL3D
|