Show bonus/malus timer text if available
[ryzomcore.git] / nel / src / 3d / ps_particle_basic.cpp
blob4425e743b1a6dcd005b296223356d4dd40938449
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "std3d.h"
22 #include "nel/3d/ps_particle_basic.h"
23 #include "nel/3d/ps_macro.h"
24 #include "nel/3d/driver.h"
25 #include "nel/3d/texture_grouped.h"
26 #include "nel/3d/texture_bump.h"
27 #include "nel/3d/texture_mem.h"
28 #include "nel/3d/particle_system.h"
31 #ifdef DEBUG_NEW
32 #define new DEBUG_NEW
33 #endif
35 namespace NL3D
40 /////////////////////////////////
41 // CPSParticle implementation //
42 /////////////////////////////////
44 //=======================================
45 CPSParticle::CPSParticle() : _DisableAutoLOD(false),
46 _UsesGlobalColorLighting(false)
48 NL_PS_FUNC(CPSParticle_CPSParticle)
51 //=======================================
52 void CPSParticle::showTool()
54 NL_PS_FUNC(CPSParticle_showTool)
55 PARTICLES_CHECK_MEM;
57 CVector I = CVector::I;
58 CVector J = CVector::J;
60 const CVector tab[] = { 2 * J, I + J
61 , I + J, 2 * I + J
62 , 2 * I + J, I
63 , I, 2 * I - J
64 , 2 * I - J, - .5f * J
65 , - .5f * J, -2 * I - J
66 , -2 * I - J, - I
67 , - I, -2 * I + J
68 , -2 * I + J, - I + J
69 , - I + J, 2 * J
71 const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
73 const float sSize = 0.1f;
74 displayIcon2d(tab, tabSize, sSize);
76 PARTICLES_CHECK_MEM;
79 //=======================================
80 void CPSParticle::computeSrcStep(uint32 &step, uint &numToProcess)
82 NL_PS_FUNC(CPSParticle_computeSrcStep)
83 nlassert(_Owner && _Owner->getOwner());
84 const CParticleSystem &ps = *(_Owner->getOwner());
85 if (_DisableAutoLOD || !ps.isAutoLODEnabled() || !ps.isSharingEnabled() || _Owner->getSize() == 0) // Should Auto-LOD be used ?
87 step = (1 << 16);
88 numToProcess = _Owner->getSize();
90 else
92 float oneMinusLODRatio = ps.getOneMinusCurrentLODRatio();
93 float LODRatio = 1.f - oneMinusLODRatio;
94 if (LODRatio > ps.getAutoLODStartDistPercent())
96 float factor = (LODRatio - 1.f) / (ps.getAutoLODStartDistPercent() - 1.f);
97 NLMISC::clamp(factor, 0.f, 1.f);
98 float r = factor;
99 for (uint k = 1; k < ps.getAutoLODDegradationExponent(); ++k)
101 r *= factor;
103 numToProcess = (uint) (_Owner->getSize() * r);
104 if (numToProcess < 1) { numToProcess = 1; }
106 step = ps.getAutoLODMode() ? // skip or limit number, depending on the mode
107 (_Owner->getSize() << 16) / numToProcess : // skip particles
108 (1 << 16); // just display less particles
110 else
112 step = (1 << 16);
113 numToProcess = _Owner->getSize();
119 //////////////////////////////////////
120 // coloured particle implementation //
121 //////////////////////////////////////
123 //=======================================
124 void CPSColoredParticle::setColorScheme(CPSAttribMaker<CRGBA> *col)
126 NL_PS_FUNC(CPSColoredParticle_setColorScheme)
127 nlassert(col);
128 delete _ColorScheme;
129 _ColorScheme = col;
130 if (getColorOwner() && col->hasMemory()) col->resize(getColorOwner()->getMaxSize(), getColorOwner()->getSize());
131 updateMatAndVbForColor();
134 //=======================================
135 void CPSColoredParticle::setColor(NLMISC::CRGBA col)
137 NL_PS_FUNC(CPSColoredParticle_setColor)
138 delete _ColorScheme;
139 _ColorScheme = NULL;
140 _Color = col;
141 updateMatAndVbForColor();
144 //=======================================
145 CPSColoredParticle::CPSColoredParticle() : _Color(CRGBA(255, 255, 255)), _ColorScheme(NULL)
147 NL_PS_FUNC(CPSColoredParticle_CPSColoredParticle)
150 //=======================================
151 CPSColoredParticle::~CPSColoredParticle()
153 NL_PS_FUNC(CPSColoredParticle_CPSColoredParticleDtor)
154 delete _ColorScheme;
157 //=======================================
158 void CPSColoredParticle::serialColorScheme(NLMISC::IStream &f)
160 NL_PS_FUNC(CPSColoredParticle_IStream )
161 f.serialVersion(1);
162 if (f.isReading())
164 if (_ColorScheme)
166 delete _ColorScheme;
167 _ColorScheme = NULL;
170 bool useColorScheme = _ColorScheme != NULL;
171 f.serial(useColorScheme);
172 if (useColorScheme)
174 f.serialPolyPtr(_ColorScheme);
176 else
178 f.serial(_Color);
182 ///////////////////////////////////
183 // sized particle implementation //
184 ///////////////////////////////////
186 //=======================================
187 void CPSSizedParticle::setSizeScheme(CPSAttribMaker<float> *size)
189 NL_PS_FUNC(CPSSizedParticle_setSizeScheme)
190 nlassert(size != NULL);
191 delete _SizeScheme;
192 _SizeScheme = size;
193 if (getSizeOwner() && size->hasMemory()) size->resize(getSizeOwner()->getMaxSize(), getSizeOwner()->getSize());
196 //=======================================
197 void CPSSizedParticle::setSize(float size)
199 NL_PS_FUNC(CPSSizedParticle_setSize)
200 delete _SizeScheme;
201 _SizeScheme = NULL;
202 _ParticleSize = size;
205 //=======================================
206 CPSSizedParticle::CPSSizedParticle() : _ParticleSize(0.3f), _SizeScheme(NULL)
208 NL_PS_FUNC(CPSSizedParticle_CPSSizedParticle)
211 //=======================================
212 CPSSizedParticle::~CPSSizedParticle()
214 NL_PS_FUNC(CPSSizedParticle_CPSSizedParticleDtor)
215 delete _SizeScheme;
218 //=======================================
219 void CPSSizedParticle::serialSizeScheme(NLMISC::IStream &f)
221 NL_PS_FUNC(CPSSizedParticle_serialSizeScheme)
222 f.serialVersion(1);
223 if (f.isReading())
225 if (_SizeScheme)
227 delete _SizeScheme;
228 _SizeScheme = NULL;
231 bool useSizeScheme = _SizeScheme != NULL;
232 f.serial(useSizeScheme);
233 if (useSizeScheme)
235 f.serialPolyPtr(_SizeScheme);
237 else
239 f.serial(_ParticleSize);
243 /////////////////////////////////////
244 // rotated particle implementation //
245 /////////////////////////////////////
247 float CPSRotated2DParticle::_RotTable[256 * 4];
248 bool CPSRotated2DParticle::_InitializedRotTab = false;
250 ///===================================================================================
251 void CPSRotated2DParticle::setAngle2DScheme(CPSAttribMaker<float> *angle2DScheme)
253 NL_PS_FUNC(CPSRotated2DParticle_setAngle2DScheme)
254 nlassert(angle2DScheme);
255 delete _Angle2DScheme;
256 _Angle2DScheme = angle2DScheme;
257 if (getAngle2DOwner() && angle2DScheme->hasMemory()) angle2DScheme->resize(getAngle2DOwner()->getMaxSize(), getAngle2DOwner()->getSize());
260 ///===================================================================================
261 void CPSRotated2DParticle::setAngle2D(float angle2DScheme)
263 NL_PS_FUNC(CPSRotated2DParticle_setAngle2D)
264 delete _Angle2DScheme;
265 _Angle2DScheme = NULL;
266 _Angle2D = angle2DScheme;
269 ///===================================================================================
270 CPSRotated2DParticle::CPSRotated2DParticle() : _Angle2D(0), _Angle2DScheme(NULL)
272 NL_PS_FUNC(CPSRotated2DParticle_CPSRotated2DParticle)
275 ///===================================================================================
276 CPSRotated2DParticle::~CPSRotated2DParticle()
278 NL_PS_FUNC(CPSRotated2DParticle_CPSRotated2DParticleDtor)
279 delete _Angle2DScheme;
282 ///===================================================================================
283 void CPSRotated2DParticle::serialAngle2DScheme(NLMISC::IStream &f)
285 NL_PS_FUNC(CPSRotated2DParticle_serialAngle2DScheme)
286 f.serialVersion(1);
287 if (f.isReading())
289 if (_Angle2DScheme)
291 delete _Angle2DScheme;
292 _Angle2DScheme = NULL;
295 bool useAngle2DScheme = _Angle2DScheme != NULL;
296 f.serial(useAngle2DScheme);
297 if (useAngle2DScheme)
299 f.serialPolyPtr(_Angle2DScheme);
301 else
303 f.serial(_Angle2D);
307 ///===================================================================================
308 void CPSRotated2DParticle::initRotTable(void)
310 NL_PS_FUNC(CPSRotated2DParticle_initRotTable)
311 float *ptFloat = _RotTable;
312 for (uint32 k = 0; k < 256; ++k)
314 const float ca = (float) cos(k * (1.0f / 256.0f) * 2.0f * NLMISC::Pi);
315 const float sa = (float) sin(k * (1.0f / 256.0f) * 2.0f * NLMISC::Pi);
317 *ptFloat++ = -ca - sa;
318 *ptFloat++ = -sa + ca;
320 *ptFloat++ = ca - sa;
321 *ptFloat++ = sa + ca;
323 _InitializedRotTab = true;
326 //////////////////////////////////////
327 // textured particle implementation //
328 //////////////////////////////////////
330 ///===================================================================================
331 void CPSTexturedParticle::setTextureIndexScheme(CPSAttribMaker<sint32> *animOrder)
333 NL_PS_FUNC(CPSTexturedParticle_setTextureIndexScheme)
334 nlassert(animOrder);
335 nlassert(_TexGroup); // setTextureGroup must have been called before this
336 delete _TextureIndexScheme;
337 _TextureIndexScheme = animOrder;
338 if (getTextureIndexOwner() && animOrder->hasMemory()) animOrder->resize(getTextureIndexOwner()->getMaxSize(), getTextureIndexOwner()->getSize());
341 updateMatAndVbForTexture();
344 ///===================================================================================
345 void CPSTexturedParticle::setTextureIndex(sint32 index)
347 NL_PS_FUNC(CPSTexturedParticle_setTextureIndex)
348 delete _TextureIndexScheme;
349 _TextureIndexScheme = NULL;
350 _TextureIndex = index;
353 ///===================================================================================
354 void CPSTexturedParticle::setTextureGroup(NLMISC::CSmartPtr<CTextureGrouped> texGroup)
356 NL_PS_FUNC(CPSTexturedParticle_setTextureGroup)
357 nlassert(texGroup);
358 if (_Tex)
360 _Tex = NULL;
362 _TexGroup = texGroup;
363 updateMatAndVbForTexture();
366 ///===================================================================================
367 void CPSTexturedParticle::setTexture(CSmartPtr<ITexture> tex)
369 NL_PS_FUNC(CPSTexturedParticle_setTexture)
370 delete _TextureIndexScheme;
371 _TextureIndexScheme = NULL;
372 _Tex = tex;
373 _TexGroup = NULL; // release any grouped texture if one was set before
374 updateMatAndVbForTexture();
377 ///===================================================================================
378 CPSTexturedParticle::CPSTexturedParticle() : _TexGroup(NULL),
379 _TextureIndexScheme(NULL),
380 _TextureIndex(0)
382 NL_PS_FUNC(CPSTexturedParticle_CPSTexturedParticle)
385 ///===================================================================================
386 CPSTexturedParticle::~CPSTexturedParticle()
388 NL_PS_FUNC(CPSTexturedParticle_CPSTexturedParticleDtor)
389 delete _TextureIndexScheme;
392 ///===================================================================================
393 void CPSTexturedParticle::serialTextureScheme(NLMISC::IStream &f)
395 NL_PS_FUNC(CPSTexturedParticle_serialTextureScheme)
396 f.serialVersion(1);
397 if (f.isReading())
399 if (_TextureIndexScheme)
401 delete _TextureIndexScheme;
402 _TextureIndexScheme = NULL;
403 _Tex = NULL;
404 _TexGroup = NULL;
408 bool useAnimatedTexture;
409 if (!f.isReading())
411 useAnimatedTexture = (_TexGroup != NULL);
413 f.serial(useAnimatedTexture);
414 if (useAnimatedTexture)
416 if (f.isReading())
418 CTextureGrouped *ptTex = NULL;
419 f.serialPolyPtr(ptTex);
420 _TexGroup = ptTex;
422 else
424 CTextureGrouped *ptTex = _TexGroup;
425 f.serialPolyPtr(ptTex);
428 bool useTextureIndexScheme = _TextureIndexScheme != NULL;
429 f.serial(useTextureIndexScheme);
430 if (useTextureIndexScheme)
432 f.serialPolyPtr(_TextureIndexScheme);
433 _TextureIndex = 0;
435 else
437 f.serial(_TextureIndex);
440 else
442 if (f.isReading())
444 ITexture *ptTex = NULL;
445 f.serialPolyPtr(ptTex);
446 _Tex = ptTex;
448 else
450 ITexture *ptTex = _Tex;
451 f.serialPolyPtr(ptTex);
456 ////////////////////////////////////////////////////////
457 // CPSRotated3DPlaneParticle implementation //
458 ////////////////////////////////////////////////////////
460 ///===================================================================================
461 void CPSRotated3DPlaneParticle::setPlaneBasisScheme(CPSAttribMaker<CPlaneBasis> *basisMaker)
463 NL_PS_FUNC(CPSRotated3DPlaneParticle_setPlaneBasisScheme)
464 nlassert(basisMaker);
465 delete _PlaneBasisScheme;
466 _PlaneBasisScheme = basisMaker;
467 if (getPlaneBasisOwner() && basisMaker->hasMemory()) basisMaker->resize(getPlaneBasisOwner()->getMaxSize(), getPlaneBasisOwner()->getSize());
470 ///===================================================================================
471 void CPSRotated3DPlaneParticle::setPlaneBasis(const CPlaneBasis &basis)
473 NL_PS_FUNC(CPSRotated3DPlaneParticle_setPlaneBasis)
474 delete _PlaneBasisScheme;
475 _PlaneBasisScheme = NULL;
476 _PlaneBasis = basis;
479 ///===================================================================================
480 CPSRotated3DPlaneParticle::CPSRotated3DPlaneParticle() : _PlaneBasisScheme(NULL)
482 NL_PS_FUNC(CPSRotated3DPlaneParticle_CPSRotated3DPlaneParticle)
483 _PlaneBasis.X = CVector::I;
484 _PlaneBasis.Y = CVector::J;
487 ///===================================================================================
488 CPSRotated3DPlaneParticle::~CPSRotated3DPlaneParticle()
490 NL_PS_FUNC(CPSRotated3DPlaneParticle_CPSRotated3DPlaneParticleDtor)
491 delete _PlaneBasisScheme;
494 ///===================================================================================
495 void CPSRotated3DPlaneParticle::serialPlaneBasisScheme(NLMISC::IStream &f)
497 NL_PS_FUNC(CPSRotated3DPlaneParticle_serialPlaneBasisScheme)
498 f.serialVersion(1);
499 f.serialPolyPtr(_PlaneBasisScheme);
500 bool usePlaneBasisScheme = _PlaneBasisScheme != NULL;
501 if (!usePlaneBasisScheme)
503 f.serial(_PlaneBasis);
507 ////////////////////////////////
508 // CPSMaterial implementation //
509 ////////////////////////////////
511 ///===================================================================================
512 CPSMaterial::CPSMaterial()
514 NL_PS_FUNC(CPSMaterial_CPSMaterial)
515 _Mat.setBlend(true);
516 _Mat.setBlendFunc(CMaterial::one, CMaterial::one);
517 _Mat.setZWrite(false);
520 ///===================================================================================
521 void CPSMaterial::serialMaterial(NLMISC::IStream &f)
523 NL_PS_FUNC(CPSMaterial_IStream )
524 // version 3 : added zbias
525 sint ver = f.serialVersion(3);
526 TBlendingMode m = getBlendingMode();
527 f.serialEnum(m);
528 setBlendingMode(m);
529 if (ver == 2)
531 bool zTest = isZTestEnabled();
532 f.serial(zTest);
533 enableZTest(zTest);
535 else
536 if (ver >= 3)
538 // bit 0 : ztest enabled
539 // bit 1 : 1 if zbias is not 0, in this case zbias follows
540 uint8 flags = (isZTestEnabled() ? 1 : 0) | (getZBias() != 0.f ? 2 : 0);
541 f.serial(flags);
542 enableZTest((flags & 1) != 0);
543 if (flags & 2)
545 float zBias = getZBias();
546 f.serial(zBias);
547 setZBias(zBias);
553 ///===================================================================================
554 void CPSMaterial::enableZTest(bool enabled)
556 NL_PS_FUNC(CPSMaterial_enableZTest)
557 _Mat.setZFunc(enabled ? CMaterial::less : CMaterial::always);
560 ///===================================================================================
561 bool CPSMaterial::isZTestEnabled() const
563 NL_PS_FUNC(CPSMaterial_isZTestEnabled)
564 return _Mat.getZFunc() != CMaterial::always;
567 ///===================================================================================
568 void CPSMaterial::setBlendingMode(CPSMaterial::TBlendingMode mode)
570 NL_PS_FUNC(CPSMaterial_setBlendingMode)
571 switch (mode)
573 case add:
574 _Mat.setBlend(true);
575 _Mat.setBlendFunc(CMaterial::one, CMaterial::one);
576 _Mat.setZWrite(false);
577 _Mat.setAlphaTest(false);
578 break;
579 case modulate:
580 _Mat.setBlend(true);
581 _Mat.setBlendFunc(CMaterial::zero, CMaterial::srccolor);
582 _Mat.setZWrite(false);
583 _Mat.setAlphaTest(false);
584 break;
585 case alphaBlend:
586 _Mat.setBlend(true);
587 _Mat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
588 _Mat.setZWrite(false);
589 _Mat.setAlphaTest(false);
590 break;
591 case alphaTest:
592 _Mat.setBlend(false);
593 _Mat.setZWrite(true);
594 _Mat.setAlphaTest(true);
595 break;
599 ///===================================================================================
600 CPSMaterial::TBlendingMode CPSMaterial::getBlendingMode(void) const
602 NL_PS_FUNC(CPSMaterial_getBlendingMode)
603 if (_Mat.getBlend())
605 CMaterial::TBlend srcBlend = _Mat.getSrcBlend();
606 CMaterial::TBlend destBlend = _Mat.getDstBlend();
608 if (srcBlend == CMaterial::one && destBlend == CMaterial::one) return add;
609 if (srcBlend == CMaterial::zero && destBlend == CMaterial::srccolor) return modulate;
610 if (srcBlend == CMaterial::srcalpha && destBlend == CMaterial::invsrcalpha) return alphaBlend;
612 // unrecognized mode
613 nlassert(0);
614 return alphaTest; // to avoid a warning only ...
616 else
618 return alphaTest;
622 ///===================================================================================
623 void CPSMaterial::forceModulateConstantColor(bool force, const NLMISC::CRGBA &col)
625 NL_PS_FUNC(CPSMaterial_forceModulateConstantColor)
626 if (force)
628 /// TODO : caching..
629 _Mat.texConstantColor(1, col);
630 _Mat.texEnvOpRGB(1, CMaterial::Modulate);
631 _Mat.texEnvOpAlpha(1, CMaterial::Modulate);
632 _Mat.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
633 _Mat.texEnvArg1RGB(1, CMaterial::Constant, CMaterial::SrcColor);
634 _Mat.texEnvArg0Alpha(1, CMaterial::Previous, CMaterial::SrcAlpha);
635 _Mat.texEnvArg1Alpha(1, CMaterial::Constant, CMaterial::SrcAlpha);
636 forceTexturedMaterialStages(2);
638 else
640 if (_Mat.getTexture(1) != NULL)
642 _Mat.setTexture(1, NULL);
648 ///===================================================================================
649 void CPSMaterial::forceTexturedMaterialStages(uint numStages)
651 NL_PS_FUNC(CPSMaterial_forceTexturedMaterialStages)
652 ITexture *blankTex = NULL;
653 uint k;
654 for (k = 0; k < numStages; ++k)
656 if (_Mat.getTexture(k) == NULL)
658 if (!blankTex)
660 blankTex = CTextureMem::Create1x1WhiteTex();
662 _Mat.setTexture(k, blankTex);
665 for (; k < IDRV_MAT_MAXTEXTURES; ++k)
667 if (_Mat.getTexture(k) != NULL)
669 _Mat.setTexture(k, NULL);
675 /////////////////////////////////////////////
676 // CPSMultiTexturedParticle implementation //
677 /////////////////////////////////////////////
679 //=======================================
680 bool CPSMultiTexturedParticle::_ForceBasicCaps = false;
682 //=======================================
683 CPSMultiTexturedParticle::CPSMultiTexturedParticle() : _MainOp(Add), _AlternateOp(Add), _MultiTexState(TouchFlag), _BumpFactor(1.f)
685 NL_PS_FUNC(CPSMultiTexturedParticle_CPSMultiTexturedParticle)
688 //=======================================
689 void CPSMultiTexturedParticle::enableMultiTexture(bool enabled /*= true*/)
691 NL_PS_FUNC(CPSMultiTexturedParticle_enableMultiTexture)
692 if (isMultiTextureEnabled() == enabled) return;
693 if (!enabled)
695 _Texture2 = NULL;
696 _AlternateTexture2 = NULL;
697 _MultiTexState = 0;
699 else
701 _MainOp = Modulate;
702 _TexScroll[0].set(0, 0);
703 _TexScroll[1].set(0, 0);
704 _MultiTexState = (uint8) MultiTextureEnabled;
706 touch();
709 //=======================================
710 void CPSMultiTexturedParticle::enableAlternateTex(bool enabled /*= true*/)
712 NL_PS_FUNC(CPSMultiTexturedParticle_enableAlternateTex)
713 nlassert(isMultiTextureEnabled()); // multitexturing must have been enabled first
714 if (enabled == isAlternateTexEnabled()) return;
716 if (enabled)
718 _TexScrollAlternate[0].set(0, 0);
719 _TexScrollAlternate[1].set(0, 0);
720 _AlternateOp = Modulate;
721 _MultiTexState |= (uint8) AlternateTextureEnabled;
723 else
725 _Texture2 = NULL;
726 _MultiTexState &= ~(uint8) AlternateTextureEnabled;
728 touch();
731 //=======================================
732 void CPSMultiTexturedParticle::serialMultiTex(NLMISC::IStream &f)
734 NL_PS_FUNC(CPSMultiTexturedParticle_serialMultiTex)
735 /// version 1 : bump factor
736 sint ver = f.serialVersion(1);
737 f.serial(_MultiTexState);
738 if (isMultiTextureEnabled())
740 f.serialEnum(_MainOp);
741 if (_MainOp == EnvBumpMap && ver >= 1)
743 f.serial(_BumpFactor);
745 ITexture *tex = NULL;
746 if (f.isReading())
748 f.serialPolyPtr(tex);
749 _Texture2 = tex;
751 else
753 tex = _Texture2;
754 f.serialPolyPtr(tex);
756 f.serial(_TexScroll[0], _TexScroll[1]);
758 if (isAlternateTexEnabled())
760 f.serialEnum(_AlternateOp);
761 if (f.isReading())
763 f.serialPolyPtr(tex);
764 _AlternateTexture2 = tex;
766 else
768 tex = _AlternateTexture2;
769 f.serialPolyPtr(tex);
771 f.serial(_TexScrollAlternate[0], _TexScrollAlternate[1]);
773 else
775 _AlternateTexture2 = NULL;
778 else
780 if (f.isReading())
782 _Texture2 = NULL;
783 _AlternateTexture2 = NULL;
788 //=======================================
789 void CPSMultiTexturedParticle::setupMaterial(ITexture *primary, IDriver *driver, CMaterial &mat, CVertexBuffer &vb)
791 NL_PS_FUNC(CPSMultiTexturedParticle_setupMaterial)
792 /// if bump is used, the matrix must be setupped each time (not a material field)
793 if (!_ForceBasicCaps && isMultiTextureEnabled() && _MainOp == EnvBumpMap)
795 if (driver->supportTextureAddrMode(CMaterial::OffsetTexture))
797 CTextureBump *tb = dynamic_cast<CTextureBump *>((ITexture *) _Texture2);
798 if (tb != NULL)
800 float normFactor = tb->getNormalizationFactor();
801 if (normFactor == 0.f) // have we computed the normalization factor ?
803 /// todo : caching of this value
804 tb->generate();
805 normFactor = tb->getNormalizationFactor();
806 tb->release();
808 const float bMat[] = { _BumpFactor * normFactor, 0.f, 0.f, _BumpFactor * normFactor};
809 driver->setMatrix2DForTextureOffsetAddrMode(1, bMat);
811 vb.setUVRouting(0, 1);
812 vb.setUVRouting(1, 0);
814 else if (driver->supportEMBM())
816 uint embmTex = 0;
817 const uint numTexStages = driver->getNbTextureStages();
818 for(uint k = 0; k < numTexStages; ++k)
820 vb.setUVRouting(k, 0);
821 if (driver->isEMBMSupportedAtStage(k))
823 vb.setUVRouting(k, 1);
824 if (k != (numTexStages - 1))
826 vb.setUVRouting(k + 1, 0);
828 embmTex = k;
829 break;
832 CTextureBump *tb = dynamic_cast<CTextureBump *>((ITexture *) _Texture2);
833 if (tb != NULL)
835 float normFactor = tb->getNormalizationFactor();
836 if (normFactor == 0.f) // have we computed the normalization factor ?
838 /// todo : caching of this value
839 tb->generate();
840 normFactor = tb->getNormalizationFactor();
841 tb->release();
843 const float bMat[] = { _BumpFactor * normFactor, 0.f, 0.f, _BumpFactor * normFactor};
844 driver->setEMBMMatrix(embmTex, bMat);
849 if (!isTouched() && areBasicCapsForcedLocal() == areBasicCapsForced()) return;
850 forceBasicCapsLocal(areBasicCapsForced());
851 if (!isMultiTextureEnabled())
853 mat.setTexture(0, primary);
854 mat.texEnvOpRGB(0, CMaterial::Modulate);
855 mat.setTexture(1, NULL);
857 else
859 if (_MainOp != EnvBumpMap)
861 setupMultiTexEnv(_MainOp, primary, _Texture2, mat, *driver);
862 _MultiTexState &= ~(uint8) EnvBumpMapUsed;
863 _MultiTexState &= ~(uint8) AlternateTextureUsed;
865 else
867 if (!_ForceBasicCaps && (driver->supportTextureAddrMode(CMaterial::OffsetTexture) || driver->supportEMBM())) // envbumpmap supported ?
869 CTextureBump *tb = dynamic_cast<CTextureBump *>((ITexture *) _Texture2);
870 if (tb != NULL)
872 float normFactor = tb->getNormalizationFactor();
873 if (normFactor == 0.f) // have we computed the normalization factor ?
875 /// todo : caching of this value
876 tb->generate();
877 normFactor = tb->getNormalizationFactor();
878 tb->release();
880 setupMultiTexEnv(_MainOp, primary, _Texture2, mat, *driver);
882 _MultiTexState &= ~(uint8) AlternateTextureUsed;
883 _MultiTexState |= (uint8) EnvBumpMapUsed;
885 else // switch to alternate
887 _MultiTexState |= (uint8) AlternateTextureUsed;
888 if (isAlternateTexEnabled() && _AlternateTexture2)
890 setupMultiTexEnv(_AlternateOp, primary, _AlternateTexture2, mat, *driver);
892 else
894 mat.setTexture(0, primary);
895 mat.texEnvOpRGB(0, CMaterial::Modulate);
897 _MultiTexState &= ~(uint8) EnvBumpMapUsed;
901 updateTexWrapMode(*driver);
902 unTouch();
905 //=======================================
906 void CPSMultiTexturedParticle::setupMultiTexEnv(TOperator op, ITexture *tex1, ITexture *tex2, CMaterial &mat, IDriver &drv)
908 NL_PS_FUNC(CPSMultiTexturedParticle_setupMultiTexEnv)
909 switch (op)
911 case Add:
912 mat.setTexture(0, tex1);
913 mat.setTexture(1, tex2);
914 mat.texEnvOpRGB(0, CMaterial::Modulate);
915 mat.texEnvOpRGB(1, CMaterial::Add);
916 mat.enableTexAddrMode(false);
917 break;
918 case Modulate:
919 mat.setTexture(0, tex1);
920 mat.setTexture(1, tex2);
921 mat.texEnvOpRGB(0, CMaterial::Modulate);
922 mat.texEnvOpRGB(1, CMaterial::Modulate);
923 mat.enableTexAddrMode(false);
924 break;
925 case EnvBumpMap:
926 if (drv.supportTextureAddrMode(CMaterial::OffsetTexture))
928 mat.setTexture(0, tex2);
929 mat.setTexture(1, tex1);
930 mat.texEnvOpRGB(0, CMaterial::Replace);
931 mat.texEnvOpRGB(1, CMaterial::Modulate);
932 mat.enableTexAddrMode(true);
933 mat.setTexAddressingMode(0, CMaterial::FetchTexture);
934 mat.setTexAddressingMode(1, CMaterial::OffsetTexture);
936 else if (drv.supportEMBM())
938 const uint numTexStages = drv.getNbTextureStages();
939 // if embm unit is at last stage, it operates on texture at previous stage
940 // otherwise it operates on texture at next stage
941 for(uint k = 0; k < numTexStages; ++k)
943 if (drv.isEMBMSupportedAtStage(k))
945 if (k == (numTexStages - 1))
947 mat.setTexture(k, tex2);
948 mat.texEnvOpRGB(k, CMaterial::EMBM);
949 mat.texEnvOpAlpha(k, CMaterial::EMBM);
950 mat.setTexture(0, tex1);
951 mat.texEnvOpRGB(0, CMaterial::Modulate);
952 mat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
953 mat.texEnvArg1RGB(0, CMaterial::Diffuse, CMaterial::SrcColor);
954 mat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
955 mat.texEnvArg1Alpha(0, CMaterial::Diffuse, CMaterial::SrcAlpha);
957 else
959 // stage before the bump map must not be empty so fill them
960 for(uint l = 0; l < k; ++l)
962 mat.setTexture(l, tex1);
963 mat.texEnvOpRGB(l, CMaterial::Modulate);
965 mat.setTexture(k, tex2);
966 mat.texEnvOpRGB(k, CMaterial::EMBM);
967 mat.setTexture(k + 1, tex1);
968 mat.texEnvOpRGB(k + 1, CMaterial::Modulate);
969 mat.texEnvArg0RGB(k + 1, CMaterial::Texture, CMaterial::SrcColor);
970 mat.texEnvArg1RGB(k + 1, CMaterial::Diffuse, CMaterial::SrcColor);
971 mat.texEnvArg0Alpha(k + 1, CMaterial::Texture, CMaterial::SrcAlpha);
972 mat.texEnvArg1Alpha(k + 1, CMaterial::Diffuse, CMaterial::SrcAlpha);
974 break;
978 break;
979 case Decal:
980 mat.setTexture(0, tex1);
981 mat.texEnvOpRGB(0, CMaterial::Replace);
982 mat.setTexture(1, NULL);
983 mat.enableTexAddrMode(false);
984 break;
985 default: break;
989 //=====static func to convert a texture to a bumpmap
990 static void ConvertToBumpMap(NLMISC::CSmartPtr<ITexture> &ptr)
992 NL_PS_FUNC(ConvertToBumpMap)
993 if (!dynamic_cast<CTextureBump *>( (ITexture *) ptr))
995 // convert to a bumpmap
996 CTextureBump *tb = new CTextureBump;
997 tb->setHeightMap((ITexture *) ptr);
998 tb->enableSharing(true);
999 ptr = tb;
1003 //=====static func to convert a bumpmap to a texture (its heightmap)
1004 static void ConvertFromBumpMap(NLMISC::CSmartPtr<ITexture> &ptr)
1006 NL_PS_FUNC(ConvertFromBumpMap)
1007 CTextureBump *bm = dynamic_cast<CTextureBump *>( (ITexture *) ptr);
1008 if (bm)
1010 // retrieve the heightmap from the bumpmap
1011 NLMISC::CSmartPtr<ITexture> hm = bm->getHeightMap();
1012 ptr = hm;
1016 //=========================================
1017 void CPSMultiTexturedParticle::setTexture2Alternate(ITexture *tex)
1019 NL_PS_FUNC(CPSMultiTexturedParticle_setTexture2Alternate)
1020 _AlternateTexture2 = tex;
1021 if (_AlternateOp != EnvBumpMap)
1023 ConvertFromBumpMap(_AlternateTexture2);
1025 else
1027 ConvertToBumpMap(_AlternateTexture2);
1029 touch();
1032 //==========================================
1033 void CPSMultiTexturedParticle::setTexture2(ITexture *tex)
1035 NL_PS_FUNC(CPSMultiTexturedParticle_setTexture2)
1036 _Texture2 = tex;
1037 if (_MainOp != EnvBumpMap)
1039 ConvertFromBumpMap(_Texture2);
1041 else
1043 if (!dynamic_cast<NL3D::CTextureBump *>((ITexture *) _Texture2))
1045 ConvertToBumpMap(_Texture2);
1048 touch();
1051 //==========================================
1052 void CPSMultiTexturedParticle::setMainTexOp(TOperator op)
1054 NL_PS_FUNC(CPSMultiTexturedParticle_setMainTexOp)
1055 _MainOp = op;
1056 if (_MainOp == EnvBumpMap)
1058 ConvertToBumpMap(_Texture2);
1060 else
1062 ConvertFromBumpMap(_Texture2);
1064 touch();
1067 //==========================================
1068 void CPSMultiTexturedParticle::setAlternateTexOp(TOperator op)
1070 NL_PS_FUNC(CPSMultiTexturedParticle_setAlternateTexOp)
1071 _AlternateOp = op;
1072 if (_AlternateOp == EnvBumpMap)
1074 ConvertToBumpMap(_AlternateTexture2);
1076 else
1078 ConvertFromBumpMap(_AlternateTexture2);
1080 touch();
1085 //==========================================
1086 void CPSMultiTexturedParticle::setUseLocalDate(bool use)
1088 NL_PS_FUNC(CPSMultiTexturedParticle_setUseLocalDate)
1089 if (use) _MultiTexState |= ScrollUseLocalDate;
1090 else _MultiTexState &= ~ ScrollUseLocalDate;
1094 //==========================================
1095 void CPSMultiTexturedParticle::setUseLocalDateAlt(bool use)
1097 NL_PS_FUNC(CPSMultiTexturedParticle_setUseLocalDateAlt)
1098 if (use) _MultiTexState |= ScrollUseLocalDateAlternate;
1099 else _MultiTexState &= ~ ScrollUseLocalDateAlternate;
1102 //==========================================
1103 void CPSTexturedParticle::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest)
1105 NL_PS_FUNC(CPSTexturedParticle_enumTexs)
1106 if (_Tex)
1108 dest.push_back(_Tex);
1110 if (getTextureGroup())
1112 dest.push_back(getTextureGroup());
1116 //==========================================
1117 void CPSMultiTexturedParticle::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
1119 NL_PS_FUNC(CPSMultiTexturedParticle_enumTexs)
1120 if (_MainOp == EnvBumpMap && !_ForceBasicCaps)
1122 if (drv.supportTextureAddrMode(CMaterial::OffsetTexture) || drv.supportEMBM())
1124 if (_Texture2) dest.push_back(_Texture2);
1126 else
1128 if (_AlternateTexture2) dest.push_back(_AlternateTexture2);
1130 return;
1132 if (_Texture2) dest.push_back(_Texture2);
1135 // *****************************************************************************************************
1136 bool CPSMultiTexturedParticle::isAlternateTextureUsed(IDriver &driver) const
1138 NL_PS_FUNC(CPSMultiTexturedParticle_isAlternateTextureUsed)
1139 if (!isTouched() && areBasicCapsForcedLocal() == areBasicCapsForced()) return (_MultiTexState & AlternateTextureUsed) != 0;
1140 if (_MainOp != EnvBumpMap) return false;
1141 return _ForceBasicCaps || (!driver.supportTextureAddrMode(CMaterial::OffsetTexture) && !driver.supportEMBM());
1144 } // NL3D