// NeL - MMORPG Framework
// 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 .
#include "ig_lighter_lib.h"
#include "nel/misc/path.h"
#include "nel/../../src/pacs/retriever_bank.h"
#include "nel/../../src/pacs/global_retriever.h"
#include "nel/3d/scene_group.h"
using namespace std;
using namespace NLMISC;
using namespace NL3D;
using namespace NLPACS;
// ***************************************************************************
void CIgLighterLib::overSampleCell(CIGSurfaceLightBuild::CCellCorner &cell, uint nSampleReq,
const CLocalRetriever &localRetriever, CGlobalRetriever &globalRetriever,
sint retrieverInstanceId, const ULocalPosition &localPos, float cellSize,
float cellRaytraceDeltaZ)
{
uint sample;
nlassert(nSampleReq==2 || nSampleReq==4 || nSampleReq==8 || nSampleReq==16);
nlassert(nSampleReq<=CInstanceLighter::MaxOverSamples);
// Compute all localPosition according to overSampleGrid.
//----------------
float s2= cellSize/2;
float s4= cellSize/4;
float s8= cellSize/8;
ULocalPosition localSamplePos[CInstanceLighter::MaxOverSamples];
// copy from localPos. Surface and estimation.
for(sample= 0; sample obstacles;
// only if Shadowing On.
if(lightDesc.Shadow)
{
// Map of shape to load
std::map shapeMap;
// For all instances of igIn.
for(i=0; i<(sint)igIn.getNumInstance();i++)
{
// progress
instanceLighter.progress("Loading Shapes obstacles", float(i)/igIn.getNumInstance());
// Skip it?? IgLighterLib use the DontCastShadowForInterior flag. See doc of this flag
if(igIn.getInstance(i).DontCastShadow || igIn.getInstance(i).DontCastShadowForInterior)
continue;
// Get the instance shape name
string name= igIn.getShapeName(i);
bool shapeFound= true;
// Try to find the shape in the UseShapeMap.
std::map::const_iterator iteMap= lightDesc.UserShapeMap.find (name);
// If not found in userShape map, try to load it from the temp loaded ShapeBank.
if( iteMap == lightDesc.UserShapeMap.end() )
{
// Add a .shape at the end ?
if (name.find('.') == std::string::npos)
name += ".shape";
// Lookup the file
string nameLookup = CPath::lookup (name, false, false);
if (!nameLookup.empty())
name = nameLookup;
// Find the shape in the bank
iteMap= shapeMap.find (name);
if (iteMap==shapeMap.end())
{
// Input file
CIFile inputFile;
if (inputFile.open (name))
{
// Load it
CShapeStream stream;
stream.serial (inputFile);
// Get the pointer
iteMap=shapeMap.insert (std::map::value_type (name, stream.getShapePointer ())).first;
}
else
{
// Error
nlwarning ("WARNING can't load shape %s\n", name.c_str());
shapeFound= false;
}
}
}
if(shapeFound)
{
CMatrix matInst;
matInst.setPos(igIn.getInstancePos(i));
matInst.setRot(igIn.getInstanceRot(i));
matInst.scale(igIn.getInstanceScale(i));
// Add triangles of this shape
CInstanceLighter::addTriangles(*iteMap->second, matInst, obstacles, i);
}
}
// Clean Up shapes.
//-----------
std::map::iterator iteMap;
iteMap= shapeMap.begin();
while(iteMap!= shapeMap.end())
{
// delte shape
delete iteMap->second;
// delete entry in map
shapeMap.erase(iteMap);
// next
iteMap= shapeMap.begin();
}
}
// Add pointLights of the IG.
for(i=0; i<(sint)igIn.getPointLightList().size();i++)
{
instanceLighter.addStaticPointLight( igIn.getPointLightList()[i], igName );
}
// Setup a CIGSurfaceLightBuild if needed.
//=======
CIGSurfaceLightBuild *igSurfaceLightBuild= NULL;
CGlobalRetriever *globalRetriever= slInfo.GlobalRetriever;
CRetrieverBank *retrieverBank= slInfo.RetrieverBank;
float cellSurfaceLightSize= slInfo.CellSurfaceLightSize;
if(retrieverBank && globalRetriever)
{
igSurfaceLightBuild= new CIGSurfaceLightBuild;
igSurfaceLightBuild->CellSize= cellSurfaceLightSize;
// col Identifier.
string colIdent= slInfo.ColIdentifierPrefix + slInfo.IgFileName + slInfo.ColIdentifierSuffix;
// For any retreiverInstance with this identifier.
//----------------
uint numInstances= globalRetriever->getInstances().size();
for(uint instanceId=0; instanceIdgetInstance(instanceId);
// If this instance is an interior
if ( instance.getType() == CLocalRetriever::Interior )
{
uint localRetrieverId= instance.getRetrieverId();
const CLocalRetriever &localRetriever= retrieverBank->getRetriever(localRetrieverId);
// get the identifer of this localRetriever
string retIdent= localRetriever.getIdentifier();
// Match the ident??
if( retIdent.find(colIdent)!=string::npos )
{
// check CRetrieverLightGrid not already present
CIGSurfaceLightBuild::ItRetrieverGridMap itRgm;
itRgm= igSurfaceLightBuild->RetrieverGridMap.find(localRetrieverId);
if( itRgm != igSurfaceLightBuild->RetrieverGridMap.end() )
{
nlwarning ("ERROR Found 2 different collision retriever with same identifier: '%s'. The 2nd is discared\n", retIdent.c_str());
}
else
{
// Append CRetrieverLightGrid.
itRgm= igSurfaceLightBuild->RetrieverGridMap.insert(
make_pair(localRetrieverId, CIGSurfaceLightBuild::CRetrieverLightGrid() ) ).first;
CIGSurfaceLightBuild::CRetrieverLightGrid &rlg= itRgm->second;
// Resize Grids.
uint numSurfaces= localRetriever.getSurfaces().size();
rlg.Grids.resize( numSurfaces );
// Compute the bbox for all surfaces. (NB: local to the localRetriever).
vector surfaceBBoxes;
localRetriever.buildInteriorSurfaceBBoxes(surfaceBBoxes);
// For each surface, compute it.
for(uint surfaceId=0; surfaceIdgetGlobalPosition(globalPos);
// Add a delta to simulate entity center
cell.CenterPos.z+= slInfo.CellRaytraceDeltaZ;
// OverSample
if(lightDesc.OverSampling==0)
{
// No OverSample, just add CenterPos to the samples.
cell.NumOverSamples= 1;
cell.OverSamples[0]= cell.CenterPos;
}
else
{
// OverSample.
overSampleCell(cell, lightDesc.OverSampling, localRetriever,
*globalRetriever, instanceId, localPos, cellSurfaceLightSize,
slInfo.CellRaytraceDeltaZ);
// it is possible that no samples lies in surfaces (small surface).
// In this case, just copy CenterPos into samples.
if(cell.NumOverSamples==0)
{
cell.NumOverSamples= 1;
cell.OverSamples[0]= cell.CenterPos;
}
}
}
else
{
// For debug mesh only, get an approximate pos.
cell.CenterPos= localPos.Estimation + instance.getOrigin();
cell.CenterPos.z+= slInfo.CellRaytraceDeltaZ;
}
// Init cell defaults
cell.Dilated= false;
cell.SunContribution= 0;
}
}
}
}
}
}
}
}
// Run.
//=======
instanceLighter.light(igIn, igOut, lightDesc, obstacles, NULL, igSurfaceLightBuild);
// Output a debug mesh??
if(igSurfaceLightBuild && slInfo.BuildDebugSurfaceShape && !igSurfaceLightBuild->RetrieverGridMap.empty() )
{
// Do it for the sun and point lights.
for(uint i=0;i<2;i++)
{
// compute
CMesh::CMeshBuild meshBuild;
CMeshBase::CMeshBaseBuild meshBaseBuild;
CVector deltaPos= CVector::Null;
deltaPos.z= - slInfo.CellRaytraceDeltaZ + 0.1f;
// What kind of debug?
if( i==0 )
igSurfaceLightBuild->buildSunDebugMesh(meshBuild, meshBaseBuild, deltaPos);
else
igSurfaceLightBuild->buildPLDebugMesh(meshBuild, meshBaseBuild, deltaPos, igOut);
// build
CMesh mesh;
mesh.build(meshBaseBuild, meshBuild);
// Save.
CShapeStream shapeStream;
shapeStream.setShapePointer(&mesh);
COFile file;
if( i==0 )
file.open(slInfo.DebugSunName);
else
file.open(slInfo.DebugPLName);
shapeStream.serial(file);
}
}
// Clean.
//=======
if(igSurfaceLightBuild)
delete igSurfaceLightBuild;
}