Linux multi-monitor fullscreen support
[ryzomcore.git] / nel / src / 3d / ps_light.cpp
blob48e57928374e32248f874e6eed5f09b77e68c8f2
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
18 #include "std3d.h"
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"
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 namespace NL3D
36 // ***************************************************************************************************************
37 CPSLight::CPSLight() : _Color(CRGBA::White),
38 _ColorScheme(NULL),
39 _AttenStart(0.1f),
40 _AttenStartScheme(NULL),
41 _AttenEnd(1.f),
42 _AttenEndScheme(NULL)
44 NL_PS_FUNC(CPSLight_CPSLight)
47 // ***************************************************************************************************************
48 CPSLight::~CPSLight()
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]);
59 else
61 #ifdef NL_DEBUG
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!
67 #endif
69 delete _ColorScheme;
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);
82 // color
83 bool hasColorScheme = _ColorScheme != NULL;
84 f.serial(hasColorScheme);
85 if (hasColorScheme)
87 f.serialPolyPtr(_ColorScheme);
89 else
91 f.serial(_Color);
93 // Atten start
94 bool hasAttenStartScheme = _AttenStartScheme != NULL;
95 f.serial(hasAttenStartScheme);
96 if (hasAttenStartScheme)
98 f.serialPolyPtr(_AttenStartScheme);
100 else
102 f.serial(_AttenStart);
104 // Atten end
105 bool hasAttenEndScheme = _AttenEndScheme != NULL;
106 f.serial(hasAttenEndScheme);
107 if (hasAttenEndScheme)
109 f.serialPolyPtr(_AttenEndScheme);
111 else
113 f.serial(_AttenEnd);
116 // save # of lights
117 if (ver == 0)
119 uint32 dummyNumLights; // from old buggy version
120 f.serial(dummyNumLights);
122 if (f.isReading())
124 if (_Owner)
126 resize(_Owner->getMaxSize());
127 for(uint k = 0; k < _Owner->getSize(); ++k)
129 CPSEmitterInfo ei;
130 ei.setDefaults();
131 newElement(ei);
134 else
136 resize(0);
141 // ***************************************************************************************************************
142 uint32 CPSLight::getType(void) const
144 NL_PS_FUNC(CPSLight_getType)
145 return PSLight;
148 // ***************************************************************************************************************
149 void CPSLight::onShow(bool shown)
151 for(uint k = 0; k < _Lights.getSize(); ++k)
153 if (_Lights[k])
155 if (shown)
157 _Lights[k]->show();
159 else
161 _Lights[k]->hide();
167 // ***************************************************************************************************************
168 void CPSLight::step(TPSProcessPass pass)
170 NL_PS_FUNC(CPSLight_step)
171 if (pass != PSMotion)
173 if (pass == PSToolRender)
175 show();
177 return;
179 nlassert(_Owner);
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);
196 // compute colors
197 NLMISC::CRGBA *colPointer;
198 uint colStride;
199 if (_ColorScheme)
201 colPointer = (CRGBA *) _ColorScheme->make(_Owner, _Lights.getSize() - numLeftLights, colors, sizeof(CRGBA), toProcess, true);
202 colStride = 1;
204 else
206 colPointer = &_Color;
207 colStride = 0;
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;
217 else
219 attenStartPointer = &_AttenStart;
220 attenStartStride = 0;
222 // compute end attenuation
223 float *attenEndPointer;
224 uint attenEndStride;
225 if (_AttenEndScheme)
227 attenEndPointer = (float *) _AttenEndScheme->make(_Owner, _Lights.getSize() - numLeftLights, attenEnd, sizeof(float), toProcess, true);
228 attenEndStride = 1;
230 else
232 attenEndPointer = &_AttenEnd;
233 attenEndStride = 0;
235 numLeftLights -= toProcess;
238 if (!*lightIt)
240 // light not created, create it from scene
241 if (scene)
243 *lightIt = NLMISC::safe_cast<CPointLightModel *>(scene->createModel(PointLightModelId));
244 if (*lightIt)
246 (*lightIt)->setTransformMode(CTransform::RotEuler);
250 if (*lightIt)
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())
262 plm->show();
264 else
266 plm->hide();
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;
287 ++ lightIt;
288 ++ posIt;
290 while(--toProcess);
294 // ***************************************************************************************************************
295 void CPSLight::setColor(NLMISC::CRGBA color)
297 NL_PS_FUNC(CPSLight_setColor)
298 delete _ColorScheme;
299 _ColorScheme = NULL;
300 _Color = color;
303 // ***************************************************************************************************************
304 void CPSLight::setColorScheme(CPSAttribMaker<NLMISC::CRGBA> *scheme)
306 NL_PS_FUNC(CPSLight_setColorScheme)
307 delete _ColorScheme;
308 _ColorScheme = scheme;
309 if (_Owner)
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;
331 if (_Owner)
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;
343 _AttenEnd = radius;
346 // ***************************************************************************************************************
347 void CPSLight::setAttenEndScheme(CPSAttribMaker<float> *scheme)
349 NL_PS_FUNC(CPSLight_setAttenEndScheme)
350 delete _AttenEndScheme;
351 _AttenEndScheme = scheme;
352 if (_Owner)
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);
375 if (_Lights[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)
402 if (_Lights[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]);
406 _Lights[k] = NULL;
411 // ***************************************************************************************************************
412 void CPSLight::show()
414 NL_PS_FUNC(CPSLight_show)
415 uint32 index;
416 CPSLocated *loc;
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);
450 } // namespace NL3D