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/ps_light.h"
20 #include "nel/3d/point_light_model.h"
21 #include "nel/3d/scene.h"
22 #include "nel/3d/particle_system.h"
23 #include "nel/3d/particle_system_model.h"
24 #include "nel/3d/ps_util.h"
25 #include "nel/misc/matrix.h"
26 #include "nel/misc/vector.h"
36 // ***************************************************************************************************************
37 CPSLight::CPSLight() : _Color(CRGBA::White
),
40 _AttenStartScheme(NULL
),
44 NL_PS_FUNC(CPSLight_CPSLight
)
47 // ***************************************************************************************************************
50 NL_PS_FUNC(CPSLight_CPSLight
)
51 if (_Owner
&& _Owner
->getOwner())
53 // check that all lights have been deleted
54 for(uint k
= 0; k
< _Lights
.getSize(); ++k
)
56 if (_Lights
[k
]) _Owner
->getOwner()->getScene()->deleteModel(_Lights
[k
]);
62 // check that all lights have been deleted
63 for(uint k
= 0; k
< _Lights
.getSize(); ++k
)
65 nlassert(_Lights
[k
] == NULL
); // error there's leak!
70 delete _AttenStartScheme
;
71 delete _AttenEndScheme
;
74 // ***************************************************************************************************************
75 void CPSLight::serial(NLMISC::IStream
&f
)
77 NL_PS_FUNC(CPSLight_serial
)
78 CPSLocatedBindable::serial(f
);
79 // version 1 : in version 0, scheme where not resized correctly; Fixed in this version
80 // version 0 : color, start attenuation radius, end attenuation radius.
81 sint ver
= f
.serialVersion(1);
83 bool hasColorScheme
= _ColorScheme
!= NULL
;
84 f
.serial(hasColorScheme
);
87 f
.serialPolyPtr(_ColorScheme
);
94 bool hasAttenStartScheme
= _AttenStartScheme
!= NULL
;
95 f
.serial(hasAttenStartScheme
);
96 if (hasAttenStartScheme
)
98 f
.serialPolyPtr(_AttenStartScheme
);
102 f
.serial(_AttenStart
);
105 bool hasAttenEndScheme
= _AttenEndScheme
!= NULL
;
106 f
.serial(hasAttenEndScheme
);
107 if (hasAttenEndScheme
)
109 f
.serialPolyPtr(_AttenEndScheme
);
119 uint32 dummyNumLights
; // from old buggy version
120 f
.serial(dummyNumLights
);
126 resize(_Owner
->getMaxSize());
127 for(uint k
= 0; k
< _Owner
->getSize(); ++k
)
141 // ***************************************************************************************************************
142 uint32
CPSLight::getType(void) const
144 NL_PS_FUNC(CPSLight_getType
)
148 // ***************************************************************************************************************
149 void CPSLight::onShow(bool shown
)
151 for(uint k
= 0; k
< _Lights
.getSize(); ++k
)
167 // ***************************************************************************************************************
168 void CPSLight::step(TPSProcessPass pass
)
170 NL_PS_FUNC(CPSLight_step
)
171 if (pass
!= PSMotion
)
173 if (pass
== PSToolRender
)
180 nlassert(_Owner
->getOwner());
181 CScene
*scene
= _Owner
->getOwner()->getScene();
182 const uint32 BATCH_SIZE
= 512;
183 uint32 numLeftLights
= _Lights
.getSize();
184 // avoid ctor call for color array
185 uint8 colorArray
[BATCH_SIZE
* sizeof(NLMISC::CRGBA
)];
186 NLMISC::CRGBA
*colors
= (NLMISC::CRGBA
*) colorArray
;
187 float attenStart
[BATCH_SIZE
];
188 float attenEnd
[BATCH_SIZE
];
189 CPSAttrib
<CPointLightModel
*>::iterator lightIt
= _Lights
.begin();
190 const CMatrix
*convMat
= &(getLocalToWorldMatrix());
191 TPSAttribVector::const_iterator posIt
= _Owner
->getPos().begin();
192 CRGBA globalColor
= _Owner
->getOwner()->getGlobalColor();
193 while (numLeftLights
)
195 uint32 toProcess
= std::min(numLeftLights
, BATCH_SIZE
);
197 NLMISC::CRGBA
*colPointer
;
201 colPointer
= (CRGBA
*) _ColorScheme
->make(_Owner
, _Lights
.getSize() - numLeftLights
, colors
, sizeof(CRGBA
), toProcess
, true);
206 colPointer
= &_Color
;
209 // compute start attenuation
210 float *attenStartPointer
;
211 uint attenStartStride
;
212 if (_AttenStartScheme
)
214 attenStartPointer
= (float *) _AttenStartScheme
->make(_Owner
, _Lights
.getSize() - numLeftLights
, attenStart
, sizeof(float), toProcess
, true);
215 attenStartStride
= 1;
219 attenStartPointer
= &_AttenStart
;
220 attenStartStride
= 0;
222 // compute end attenuation
223 float *attenEndPointer
;
227 attenEndPointer
= (float *) _AttenEndScheme
->make(_Owner
, _Lights
.getSize() - numLeftLights
, attenEnd
, sizeof(float), toProcess
, true);
232 attenEndPointer
= &_AttenEnd
;
235 numLeftLights
-= toProcess
;
240 // light not created, create it from scene
243 *lightIt
= NLMISC::safe_cast
<CPointLightModel
*>(scene
->createModel(PointLightModelId
));
246 (*lightIt
)->setTransformMode(CTransform::RotEuler
);
252 NLMISC::CVector pos
= *convMat
* *posIt
;
253 CPointLightModel
*plm
= *lightIt
;
254 if (pos
!= plm
->getPos()) plm
->setPos(pos
);
257 if (CParticleSystem::OwnerModel
)
259 // make sure the visibility is the same
260 if (CParticleSystem::OwnerModel
->isHrcVisible())
268 plm
->setClusterSystem(CParticleSystem::OwnerModel
->getClusterSystem());
271 CRGBA newCol
= *colPointer
;
272 newCol
.modulateFromColor(newCol
, globalColor
);
273 if (newCol
!= plm
->PointLight
.getDiffuse())
275 plm
->PointLight
.setColor(newCol
);
277 colPointer
+= colStride
;
278 if (*attenStartPointer
!= plm
->PointLight
.getAttenuationBegin()
279 || *attenEndPointer
!= plm
->PointLight
.getAttenuationEnd()
282 plm
->PointLight
.setupAttenuation(*attenStartPointer
, *attenEndPointer
);
284 attenStartPointer
+= attenStartStride
;
285 attenEndPointer
+= attenEndStride
;
294 // ***************************************************************************************************************
295 void CPSLight::setColor(NLMISC::CRGBA color
)
297 NL_PS_FUNC(CPSLight_setColor
)
303 // ***************************************************************************************************************
304 void CPSLight::setColorScheme(CPSAttribMaker
<NLMISC::CRGBA
> *scheme
)
306 NL_PS_FUNC(CPSLight_setColorScheme
)
308 _ColorScheme
= scheme
;
311 if (_ColorScheme
&& _ColorScheme
->hasMemory()) _ColorScheme
->resize(_Owner
->getMaxSize(), _Owner
->getSize());
315 // ***************************************************************************************************************
316 void CPSLight::setAttenStart(float radius
)
318 NL_PS_FUNC(CPSLight_setAttenStart
)
319 nlassert(radius
> 0.f
);
320 delete _AttenStartScheme
;
321 _AttenStartScheme
= NULL
;
322 _AttenStart
= radius
;
325 // ***************************************************************************************************************
326 void CPSLight::setAttenStartScheme(CPSAttribMaker
<float> *scheme
)
328 NL_PS_FUNC(CPSLight_setAttenStartScheme
)
329 delete _AttenStartScheme
;
330 _AttenStartScheme
= scheme
;
333 if (_AttenStartScheme
&& _AttenStartScheme
->hasMemory()) _AttenStartScheme
->resize(_Owner
->getMaxSize(), _Owner
->getSize());
337 // ***************************************************************************************************************
338 void CPSLight::setAttenEnd(float radius
)
340 NL_PS_FUNC(CPSLight_setAttenEnd
)
341 delete _AttenEndScheme
;
342 _AttenEndScheme
= NULL
;
346 // ***************************************************************************************************************
347 void CPSLight::setAttenEndScheme(CPSAttribMaker
<float> *scheme
)
349 NL_PS_FUNC(CPSLight_setAttenEndScheme
)
350 delete _AttenEndScheme
;
351 _AttenEndScheme
= scheme
;
354 if (_AttenEndScheme
&& _AttenEndScheme
->hasMemory()) _AttenEndScheme
->resize(_Owner
->getMaxSize(), _Owner
->getSize());
358 // ***************************************************************************************************************
359 void CPSLight::newElement(const CPSEmitterInfo
&info
)
361 NL_PS_FUNC(CPSLight_newElement
)
362 if (_ColorScheme
&& _ColorScheme
->hasMemory()) _ColorScheme
->newElement(info
);
363 if (_AttenStartScheme
&& _AttenStartScheme
->hasMemory()) _AttenStartScheme
->newElement(info
);
364 if (_AttenEndScheme
&& _AttenEndScheme
->hasMemory()) _AttenEndScheme
->newElement(info
);
365 _Lights
.insert(NULL
); // instance is created during step()
368 // ***************************************************************************************************************
369 void CPSLight::deleteElement(uint32 index
)
371 NL_PS_FUNC(CPSLight_deleteElement
)
372 if (_ColorScheme
&& _ColorScheme
->hasMemory()) _ColorScheme
->deleteElement(index
);
373 if (_AttenStartScheme
&& _AttenStartScheme
->hasMemory()) _AttenStartScheme
->deleteElement(index
);
374 if (_AttenEndScheme
&& _AttenEndScheme
->hasMemory()) _AttenEndScheme
->deleteElement(index
);
377 nlassert(_Owner
&& _Owner
->getScene());
378 _Owner
->getScene()->deleteModel(_Lights
[index
]);
380 _Lights
.remove(index
);
383 // ***************************************************************************************************************
384 void CPSLight::resize(uint32 size
)
386 NL_PS_FUNC(CPSLight_resize
)
387 nlassert(size
< (1 << 16));
388 if (_ColorScheme
&& _ColorScheme
->hasMemory()) _ColorScheme
->resize(size
, getOwner() ? getOwner()->getSize() : 0);
389 if (_AttenStartScheme
&& _AttenStartScheme
->hasMemory()) _AttenStartScheme
->resize(size
, getOwner() ? getOwner()->getSize() : 0);
390 if (_AttenEndScheme
&& _AttenEndScheme
->hasMemory()) _AttenEndScheme
->resize(size
, getOwner() ? getOwner()->getSize() : 0);
391 _Lights
.resize(size
);
394 // ***************************************************************************************************************
395 void CPSLight::releaseAllRef()
397 NL_PS_FUNC(CPSLight_releaseAllRef
)
398 CPSLocatedBindable::releaseAllRef();
399 // delete all lights, because pointer to the scene is lost after detaching from a system.
400 for(uint k
= 0; k
< _Lights
.getSize(); ++k
)
404 nlassert(_Owner
&& _Owner
->getScene()); // if there's an instance there must be a scene from which it was created.
405 _Owner
->getScene()->deleteModel(_Lights
[k
]);
411 // ***************************************************************************************************************
412 void CPSLight::show()
414 NL_PS_FUNC(CPSLight_show
)
417 CPSLocatedBindable
*lb
;
418 _Owner
->getOwner()->getCurrentEditedElement(loc
, index
, lb
);
420 NLMISC::CMatrix xzMat
;
421 xzMat
.setRot(CVector::I
, CVector::K
, CVector::Null
);
422 NLMISC::CMatrix xyMat
;
423 xyMat
.setRot(CVector::I
, CVector::J
, CVector::Null
);
424 NLMISC::CMatrix yzMat
;
425 yzMat
.setRot(CVector::J
, CVector::K
, CVector::Null
);
428 getDriver()->setupModelMatrix(NLMISC::CMatrix::Identity
);
429 const uint numSubdiv
= 32;
430 // for each element, see if it is the selected element, and if yes, display in red
431 for (uint k
= 0; k
< _Lights
.getSize(); ++k
)
433 float radiusStart
= _AttenStartScheme
? _AttenStartScheme
->get(_Owner
, k
) : _AttenStart
;
434 float radiusEnd
= _AttenEndScheme
? _AttenEndScheme
->get(_Owner
, k
) : _AttenEnd
;
435 NLMISC::clamp(radiusStart
, 0.f
, radiusEnd
);
436 const NLMISC::CRGBA colStart
= (((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
) ? CRGBA::Blue
: CRGBA(0, 0, 127));
437 const NLMISC::CRGBA colEnd
= (((lb
== NULL
|| this == lb
) && loc
== _Owner
&& index
== k
) ? CRGBA::Red
: CRGBA(127, 0, 0));
439 CPSUtil::displayDisc(*getDriver(), radiusStart
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], xzMat
, numSubdiv
, colStart
);
440 CPSUtil::displayDisc(*getDriver(), radiusStart
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], xyMat
, numSubdiv
, colStart
);
441 CPSUtil::displayDisc(*getDriver(), radiusStart
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], yzMat
, numSubdiv
, colStart
);
443 CPSUtil::displayDisc(*getDriver(), radiusEnd
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], xzMat
, numSubdiv
, colEnd
);
444 CPSUtil::displayDisc(*getDriver(), radiusEnd
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], xyMat
, numSubdiv
, colEnd
);
445 CPSUtil::displayDisc(*getDriver(), radiusEnd
, getLocalToWorldMatrix() * _Owner
->getPos()[k
], yzMat
, numSubdiv
, colEnd
);