// 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 . #ifndef NL_INSTANCE_LIGHTER_H #define NL_INSTANCE_LIGHTER_H #include "nel/misc/types_nl.h" #include "nel/misc/vector.h" #include "nel/misc/triangle.h" #include "nel/misc/plane.h" #include "nel/misc/matrix.h" #include "nel/3d/scene_group.h" #include "nel/3d/landscape.h" #include "nel/3d/shape.h" #include "nel/3d/mesh.h" #include "nel/3d/mesh_mrm.h" #include "nel/3d/cube_grid.h" #include "nel/3d/ig_surface_light_build.h" namespace NL3D { // *************************************************************************** /** * A class to precompute "StaticSetup" lighting for instances in an InstanceGroup. * Class "inspired" from CZoneLighter :) * \author Lionel Berenguier * \author Nevrax France * \date 2001 */ class CInstanceLighter { public: enum {MaxOverSamples= 16}; public: // Light Options decription structure class CLightDesc { public: // Default Ctor CLightDesc (); // Disable Sun contribution: ie set 0 to all contributions of sun on instances and surfaces?? false by default bool DisableSunContribution; // Sun direction NLMISC::CVector LightDirection; // Grid size uint GridSize; // Grid size float GridCellSize; // Project shadows on instances. bool Shadow; // Number of samples For sun shadowing only. Must be: 0 (disable), 2, 4, 8, 16 uint OverSampling; // This is a user shapeMap. std::map UserShapeMap; }; // A triangle used to light the zone class CTriangle { friend class CInstanceLighter; public: // Ctors CTriangle (const NLMISC::CTriangle& triangle, sint instanceId) { Triangle=triangle; InstanceId= instanceId; } // The triangle NLMISC::CTriangle Triangle; // which instance owns this triangle. -1 if none (landscape or others ig). sint InstanceId; // Other info const NLMISC::CPlane &getPlane() const {return Plane;} private: NLMISC::CPlane Plane; }; public: /** Tool method which take a single IG, and do all the god job to light this one, with no other dependencies * NB: it uses instLighter passed, init() ing it. It use lightDesc.UserShapeMap or it load Shape in directory lightDesc.ShapePath */ static void lightIgSimple(CInstanceLighter &instLighter, const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc, const char *igName); public: /// Constructor CInstanceLighter(); /// Destructor virtual ~CInstanceLighter() {} // Init the system void init (); /** Light an InstanceGroup * igOut has different PointLights than igIn. eg: if a pointLight do not light anything, then it is not * present in igOut. * NB: shapes are used to retrieve useful info on them (center of AABBox ...) . They are taken from * lightDesc.UserShapeMap, or loaded from lightDesc.ShapePath if not found. * \param landscape if !NULL use this Landscape SunContribution, looking landscape faces under each instance, * for faster computing, and to get influence of Sky. NB: this landscape does not have to be tesselated, * but all Zones that lies under igIn should be loaded in. * \param igSurfaceLightBuild if !NULL, light() will compute igOut.IGSurfaceLight, else it is just cleared. */ void light (const CInstanceGroup &igIn, CInstanceGroup &igOut, const CLightDesc &lightDesc, std::vector& obstacles, CLandscape *landscape= NULL, CIGSurfaceLightBuild *igSurfaceLightBuild= NULL); // Add triangles from a landscape static void addTriangles (CLandscape &landscape, std::vector &listZone, uint order, std::vector& triangleArray); /** Add triangles from a transform shape. Work only for CMesh, CMultiMesh and CMeshMRM all without skinning. * Give An instanceId!=-1 only for instances of the IG to compute. This is to avoid auto-shadowing. */ static void addTriangles (const IShape &shape, const NLMISC::CMatrix& modelMT, std::vector& triangleArray, sint instanceId); // Progress callback virtual void progress (const char * /* message */, float /* progress */) {} /// \name Static PointLights mgt. //@{ /** Append a static point light to compute. call at setup stage (before light() ). * NB: you must append all PointLights of intersets, even ones from the IG to compute. */ void addStaticPointLight(const CPointLightNamed &pln, const char *igName); //@} // ******************************** private: static void addTriangles (const CMeshGeom &meshGeom, const NLMISC::CMatrix& modelMT, std::vector& triangleArray, sint instanceId); static void addTriangles (const CMeshMRMGeom &meshGeom, const NLMISC::CMatrix& modelMT, std::vector& triangleArray, sint instanceId); static void excludeAllPatchFromRefineAll (CLandscape &landscape, std::vector &listZone, bool exclude); // light / rayTrace against sun. void computeSunContribution(const CLightDesc &lightDesc, std::vector& obstacles, CLandscape *landscape); void dilateLightingOnSurfaceCells(); private: struct CPointLightRT; struct CInstanceInfo { // Center of the mesh to compute lighting. CVector CenterPos; // Pos of samples, for overSampling. if none, OverSamples[0]== CenterPos CVector OverSamples[MaxOverSamples]; // Temp light which influence this instance. CPointLightRT *Light[CInstanceGroup::NumStaticLightPerInstance]; // Temp Ambient light which influence this instance. CPointLightRT *LocalAmbientLight; }; // Instance of the current ig to be lighted. std::vector _Instances; // Instance Lighting Info of the current ig to be lighted. std::vector _InstanceInfos; // The current instance computed. Used to skip it in raytracing sint _CurrentInstanceComputed; // CIGSurfaceLight Info. CIGSurfaceLightBuild *_IGSurfaceLightBuild; // The RetrieverGridMap currently builded. CIGSurfaceLight::TRetrieverGridMap _IGRetrieverGridMap; /// A PointLight struct to test raytracing. struct CPointLightRT { CPointLightNamed PointLight; float OODeltaAttenuation; // BBox of the pointLight NLMISC::CBSphere BSphere; // Faces that may occlude the light. Only Back Faces (from the light pov) are inserted CCubeGrid FaceCubeGrid; // Number of TileLightInfluences which use this PointLight. uint RefCount; // Final id of the pointLight in the Ig. uint DstId; CPointLightRT(); /** Tells if a point is visible from this light. NB: test first if in BSphere. * If occluded or out of radius, return false, else return true. * if instanceComputed>=0, then skip obstacles with InstanceId==instanceComputed. * Also Skip if the light is an Ambient, and skip if the light is a spot and if the position is out of the cone */ bool testRaytrace(const CVector &v, sint instanceComputed= -1); }; /// For sort() struct CPredPointLightToPoint { CVector Point; bool operator() (CPointLightRT *pla, CPointLightRT *plb) const; }; /// List of PointLights std::vector _StaticPointLights; /// QuadGrid of PointLights. Builded from _StaticPointLights CQuadGrid _StaticPointLightQuadGrid; /// Fill CubeGrid, and set PointLightRT in _StaticPointLightQuadGrid. void compilePointLightRT(uint gridSize, float gridCellSize, std::vector& obstacles, bool doShadow); /** Process the IG, ie process _InstanceInfos. Also process SurfaceLightGrid * MultiCPU: not done for now. Be aware of CPointLightRT::RefCount!!!! */ void processIGPointLightRT(std::vector &listPointLight); private: /// \name Cell Iteration. ie iteration on _IGRetrieverGridMap cells and _IGSurfaceLightBuild cells // @{ void beginCell(); void nextCell(); bool isEndCell(); // get current cell iterated. CSurfaceLightGrid::CCellCorner &getCurrentCell(); // get current cellInfo iterated. CIGSurfaceLightBuild::CCellCorner &getCurrentCellInfo(); // Neighboring of the cell bool isCurrentNeighborCellInSurface(sint xnb, sint ynb); CSurfaceLightGrid::CCellCorner &getCurrentNeighborCell(sint xnb, sint ynb); CIGSurfaceLightBuild::CCellCorner &getCurrentNeighborCellInfo(sint xnb, sint ynb); uint getCurrentCellNumber() const {return _ItCurrentCellNumber;} uint getTotalCellNumber() const {return _TotalCellNumber;} void progressCell(const char *message); // Iteration Data. CIGSurfaceLight::ItRetrieverGridMap _ItRetriever; CIGSurfaceLightBuild::ItRetrieverGridMap _ItRetrieverInfo; uint _ItSurfId; uint _ItCellId; bool _IsEndCell; uint _ItCurrentCellNumber; uint _TotalCellNumber; float _LastCellProgress; // @} }; } // NL3D #endif // NL_INSTANCE_LIGHTER_H /* End of instance_lighter.h */