1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "nel/3d/point_light_model.h"
20 #include "nel/3d/light_trav.h"
21 #include "nel/3d/root_model.h"
22 #include "nel/3d/skeleton_model.h"
23 #include "nel/3d/scene.h"
26 using namespace NLMISC
;
35 // ***************************************************************************
36 void CPointLightModel::registerBasic()
38 CScene::registerModel( PointLightModelId
, TransformId
, CPointLightModel::creator
);
41 // ***************************************************************************
42 CPointLightModel::CPointLightModel()
44 _DeltaPosToSkeletonWhenOutOfFrustum
.set(0, 0, 1.5f
);
45 _TimeFromLastClippedSpotDirection
= 0;
46 _InfluenceLightMap
= false;
50 // ***************************************************************************
51 CPointLightModel::~CPointLightModel()
56 // ***************************************************************************
57 void CPointLightModel::initModel()
59 CTransform::initModel();
61 // link me to the root of light.
62 getOwnerScene()->getLightTrav().addPointLightModel(this);
67 // ***************************************************************************
68 void CPointLightModel::setDeltaPosToSkeletonWhenOutOfFrustum(const CVector
&deltaPos
)
70 _DeltaPosToSkeletonWhenOutOfFrustum
= deltaPos
;
74 // ***************************************************************************
75 const CVector
&CPointLightModel::getDeltaPosToSkeletonWhenOutOfFrustum() const
77 return _DeltaPosToSkeletonWhenOutOfFrustum
;
81 // ***************************************************************************
82 void CPointLightModel::traverseLight()
84 CLightTrav
&lightTrav
= getOwnerScene()->getLightTrav();
86 // Note: any dynamic light is supposed to always move each frame, so they are re-inserted in the
87 // quadGrid each frame.
90 // reset all models lighted by this light.
91 // Then models are marked dirty and their light setup is reseted
92 PointLight
.resetLightedModels();
95 // if the light is visible (ie not hiden)
98 // If the light is not hidden by any skeleton.
101 // recompute the worldPosition of the light.
102 PointLight
.setPosition( getWorldMatrix().getPos() );
104 // recompute the worldSpotDirection of the light.
105 if(PointLight
.getType() == CPointLight::SpotLight
)
107 // Interpolate over time. (hardcoded)
108 _TimeFromLastClippedSpotDirection
-= 0.05f
;
109 if(_TimeFromLastClippedSpotDirection
<= 0)
111 PointLight
.setupSpotDirection(getWorldMatrix().getJ());
115 CVector actualSpotDir
= getWorldMatrix().getJ();
117 float t
= _TimeFromLastClippedSpotDirection
;
118 CVector interpSpotDir
= actualSpotDir
*(1-t
) + _LastWorldSpotDirectionWhenOutOfFrustum
* t
;
119 // set the interpolated one.
120 PointLight
.setupSpotDirection(interpSpotDir
);
126 // We are hidden because a skeleton has hide us, or created during anim detail traversal (or else don't know why).
127 // NB: a point light can't be in a cluster since it is not a transformShape...
128 if (!_AncestorSkeletonModel
) return;
129 const CMatrix
&skMatrix
= _AncestorSkeletonModel
->getWorldMatrix();
131 PointLight
.setPosition( skMatrix
* _DeltaPosToSkeletonWhenOutOfFrustum
);
133 // recompute the worldSpotDirection of the light.
134 if(PointLight
.getType() == CPointLight::SpotLight
)
136 // If last frame, this pointLight was visible (Time is not 1)
137 if(_TimeFromLastClippedSpotDirection
!= 1)
139 // Take the current World spot direction
140 _LastWorldSpotDirectionWhenOutOfFrustum
= PointLight
.getSpotDirection();
142 _TimeFromLastClippedSpotDirection
= 1;
145 // Don't need to modify PointLight spot direction since already setuped (when model was visible)
149 // now, insert this light in the quadGrid. NB: in CLightTrav::traverse(), the quadGrid is cleared before here.
150 // This light will touch (resetLighting()) any model it may influence.
151 lightTrav
.LightingManager
.addDynamicLight(&PointLight
);
154 // if this light is the one that should influence the lightmapped objects
155 if(_InfluenceLightMap
)
157 // setup a light with attenuation, for more accurate vertex lighting
160 // setup position/type/direction/color
161 if(PointLight
.getType()!=CPointLight::SpotLight
)
162 vertexLight
.setupPointLight(CRGBA::Black
, PointLight
.getDiffuse(), PointLight
.getSpecular(),
163 PointLight
.getPosition(), CVector::K
);
165 vertexLight
.setupSpotLight(CRGBA::Black
, PointLight
.getDiffuse(), PointLight
.getSpecular(),
166 PointLight
.getPosition(), PointLight
.getSpotDirection(), 1, float(Pi
)/2);
169 vertexLight
.setupAttenuation(PointLight
.getAttenuationBegin(), PointLight
.getAttenuationEnd());
171 // setup hotspot for spotLight
172 if(PointLight
.getType()==CPointLight::SpotLight
)
174 // hotspot == where attenuation should be 0.9
175 vertexLight
.setupSpotExponent(PointLight
.getSpotAngleBegin()*0.9f
+ PointLight
.getSpotAngleEnd()*0.1f
);
179 getOwnerScene()->getDriver()->setLightMapDynamicLight(true, vertexLight
);