// 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 "std3d.h" #include "nel/3d/surface_light_grid.h" #include "nel/misc/common.h" #include "nel/3d/ig_surface_light.h" #include "nel/misc/fast_floor.h" #include "nel/3d/light_influence_interpolator.h" #include "nel/3d/point_light_named.h" #include "nel/3d/scene_group.h" using namespace NLMISC; namespace NL3D { // *************************************************************************** CSurfaceLightGrid::CSurfaceLightGrid() { /* *********************************************** * 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 * ***********************************************/ Width= 0; Height= 0; } // *************************************************************************** void CSurfaceLightGrid::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 * ***********************************************/ (void)f.serialVersion(0); f.serial(Origin); f.serial(Width); f.serial(Height); f.serial(Cells); } // *************************************************************************** void CSurfaceLightGrid::getStaticLightSetup(NLMISC::CRGBA sunAmbient, const CVector &localPos, std::vector &pointLightList, uint8 &sunContribution, CIGSurfaceLight &igsl, NLMISC::CRGBA &localAmbient) const { // Get local coordinate to the grid. float xfloat= (localPos.x - Origin.x) * igsl.getOOCellSize(); float yfloat= (localPos.y - Origin.y) * igsl.getOOCellSize(); sint wCell= Width-1; sint hCell= Height-1; // fastFloor: use a precision of 256 to avoid doing OptFastFloorBegin. sint wfixed= wCell<<8; sint hfixed= hCell<<8; sint xfixed= NLMISC::OptFastFloor(xfloat * 256); sint yfixed= NLMISC::OptFastFloor(yfloat * 256); clamp(xfixed, 0, wfixed); clamp(yfixed, 0, hfixed); // compute the cell coord, and the subCoord for bilinear. sint xCell, yCell, xSub, ySub; xCell= xfixed>>8; yCell= yfixed>>8; clamp(xCell, 0, wCell-1); clamp(yCell, 0, hCell-1); // Hence, xSub and ySub range is [0, 256]. xSub= xfixed - (xCell<<8); ySub= yfixed - (yCell<<8); // Use a CLightInfluenceInterpolator to biLinear light influence CLightInfluenceInterpolator interp; // Must support only 2 light per cell corner. nlassert(CSurfaceLightGrid::NumLightPerCorner==2); nlassert(CLightInfluenceInterpolator::NumLightPerCorner==2); // Get ref on array of PointLightNamed. CPointLightNamed *igPointLights= NULL;; if( igsl._Owner->getPointLightList().size() >0 ) { // const_cast, because will only change _IdInfluence, and // also because CLightingManager will call appendLightedModel() igPointLights= const_cast(&(igsl._Owner->getPointLightList()[0])); } // For 4 corners. uint x,y; uint sunContribFixed= 0; uint rLocalAmbientFixed= 0; uint gLocalAmbientFixed= 0; uint bLocalAmbientFixed= 0; uint wLocalAmbientFixed= 0; for(y=0;y<2;y++) { for(x=0;x<2;x++) { // Prepare compute for PointLights. //------------- // get ref on TLI, and on corner. const CCellCorner &cellCorner= Cells[ (yCell+y)*Width + xCell+x ]; CLightInfluenceInterpolator::CCorner &corner= interp.Corners[y*2 + x]; // For all lights uint lid; for(lid= 0; lid leave color and alpha To 0. if(cellCorner.LocalAmbientId!=0xFF) { CPointLight &pl= igPointLights[cellCorner.LocalAmbientId]; // take current ambient from pointLight CRGBA ambCorner= pl.getAmbient(); // Add with sun this one? if(pl.getAddAmbientWithSun()) ambCorner.addRGBOnly(ambCorner, sunAmbient); // bilinear rLocalAmbientFixed+= ambCorner.R * mulBi; gLocalAmbientFixed+= ambCorner.G * mulBi; bLocalAmbientFixed+= ambCorner.B * mulBi; // increase the weight influence of igPointLights wLocalAmbientFixed+= 256 * mulBi; } } } // interpolate PointLights. interp.interpolate(pointLightList, xSub/256.f, ySub/256.f); // Final SunContribution sunContribution= sunContribFixed>>16; // Final Ambient Contribution of Ambient Lights CRGBA tempAmbient; tempAmbient.R= rLocalAmbientFixed>>16; tempAmbient.G= gLocalAmbientFixed>>16; tempAmbient.B= bLocalAmbientFixed>>16; // must interpolate between SunAmbient and tempAmbient uint uAmbFactor= wLocalAmbientFixed>>16; // Blend, but tempAmbient.r/g/b is already multiplied by weight. localAmbient.modulateFromuiRGBOnly(sunAmbient, 256 - uAmbFactor); localAmbient.addRGBOnly(localAmbient, tempAmbient); } } // NL3D