1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
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
)
57 CVector I
= CVector::I
;
58 CVector J
= CVector::J
;
60 const CVector tab
[] = { 2 * J
, I
+ J
64 , 2 * I
- J
, - .5f
* J
65 , - .5f
* J
, -2 * I
- J
71 const uint tabSize
= sizeof(tab
) / (2 * sizeof(CVector
));
73 const float sSize
= 0.1f
;
74 displayIcon2d(tab
, tabSize
, sSize
);
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 ?
88 numToProcess
= _Owner
->getSize();
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
);
99 for (uint k
= 1; k
< ps
.getAutoLODDegradationExponent(); ++k
)
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
113 numToProcess
= _Owner
->getSize();
119 //////////////////////////////////////
120 // coloured particle implementation //
121 //////////////////////////////////////
123 //=======================================
124 void CPSColoredParticle::setColorScheme(CPSAttribMaker
<CRGBA
> *col
)
126 NL_PS_FUNC(CPSColoredParticle_setColorScheme
)
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
)
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
)
157 //=======================================
158 void CPSColoredParticle::serialColorScheme(NLMISC::IStream
&f
)
160 NL_PS_FUNC(CPSColoredParticle_IStream
)
170 bool useColorScheme
= _ColorScheme
!= NULL
;
171 f
.serial(useColorScheme
);
174 f
.serialPolyPtr(_ColorScheme
);
182 ///////////////////////////////////
183 // sized particle implementation //
184 ///////////////////////////////////
186 //=======================================
187 void CPSSizedParticle::setSizeScheme(CPSAttribMaker
<float> *size
)
189 NL_PS_FUNC(CPSSizedParticle_setSizeScheme
)
190 nlassert(size
!= NULL
);
193 if (getSizeOwner() && size
->hasMemory()) size
->resize(getSizeOwner()->getMaxSize(), getSizeOwner()->getSize());
196 //=======================================
197 void CPSSizedParticle::setSize(float size
)
199 NL_PS_FUNC(CPSSizedParticle_setSize
)
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
)
218 //=======================================
219 void CPSSizedParticle::serialSizeScheme(NLMISC::IStream
&f
)
221 NL_PS_FUNC(CPSSizedParticle_serialSizeScheme
)
231 bool useSizeScheme
= _SizeScheme
!= NULL
;
232 f
.serial(useSizeScheme
);
235 f
.serialPolyPtr(_SizeScheme
);
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
)
291 delete _Angle2DScheme
;
292 _Angle2DScheme
= NULL
;
295 bool useAngle2DScheme
= _Angle2DScheme
!= NULL
;
296 f
.serial(useAngle2DScheme
);
297 if (useAngle2DScheme
)
299 f
.serialPolyPtr(_Angle2DScheme
);
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
)
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
)
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
;
373 _TexGroup
= NULL
; // release any grouped texture if one was set before
374 updateMatAndVbForTexture();
377 ///===================================================================================
378 CPSTexturedParticle::CPSTexturedParticle() : _TexGroup(NULL
),
379 _TextureIndexScheme(NULL
),
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
)
399 if (_TextureIndexScheme
)
401 delete _TextureIndexScheme
;
402 _TextureIndexScheme
= NULL
;
408 bool useAnimatedTexture
;
411 useAnimatedTexture
= (_TexGroup
!= NULL
);
413 f
.serial(useAnimatedTexture
);
414 if (useAnimatedTexture
)
418 CTextureGrouped
*ptTex
= NULL
;
419 f
.serialPolyPtr(ptTex
);
424 CTextureGrouped
*ptTex
= _TexGroup
;
425 f
.serialPolyPtr(ptTex
);
428 bool useTextureIndexScheme
= _TextureIndexScheme
!= NULL
;
429 f
.serial(useTextureIndexScheme
);
430 if (useTextureIndexScheme
)
432 f
.serialPolyPtr(_TextureIndexScheme
);
437 f
.serial(_TextureIndex
);
444 ITexture
*ptTex
= NULL
;
445 f
.serialPolyPtr(ptTex
);
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
;
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
)
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
)
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();
531 bool zTest
= isZTestEnabled();
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);
542 enableZTest((flags
& 1) != 0);
545 float zBias
= getZBias();
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
)
575 _Mat
.setBlendFunc(CMaterial::one
, CMaterial::one
);
576 _Mat
.setZWrite(false);
577 _Mat
.setAlphaTest(false);
581 _Mat
.setBlendFunc(CMaterial::zero
, CMaterial::srccolor
);
582 _Mat
.setZWrite(false);
583 _Mat
.setAlphaTest(false);
587 _Mat
.setBlendFunc(CMaterial::srcalpha
, CMaterial::invsrcalpha
);
588 _Mat
.setZWrite(false);
589 _Mat
.setAlphaTest(false);
592 _Mat
.setBlend(false);
593 _Mat
.setZWrite(true);
594 _Mat
.setAlphaTest(true);
599 ///===================================================================================
600 CPSMaterial::TBlendingMode
CPSMaterial::getBlendingMode(void) const
602 NL_PS_FUNC(CPSMaterial_getBlendingMode
)
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
;
614 return alphaTest
; // to avoid a warning only ...
622 ///===================================================================================
623 void CPSMaterial::forceModulateConstantColor(bool force
, const NLMISC::CRGBA
&col
)
625 NL_PS_FUNC(CPSMaterial_forceModulateConstantColor
)
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);
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
;
654 for (k
= 0; k
< numStages
; ++k
)
656 if (_Mat
.getTexture(k
) == NULL
)
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;
696 _AlternateTexture2
= NULL
;
702 _TexScroll
[0].set(0, 0);
703 _TexScroll
[1].set(0, 0);
704 _MultiTexState
= (uint8
) MultiTextureEnabled
;
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;
718 _TexScrollAlternate
[0].set(0, 0);
719 _TexScrollAlternate
[1].set(0, 0);
720 _AlternateOp
= Modulate
;
721 _MultiTexState
|= (uint8
) AlternateTextureEnabled
;
726 _MultiTexState
&= ~(uint8
) AlternateTextureEnabled
;
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
;
748 f
.serialPolyPtr(tex
);
754 f
.serialPolyPtr(tex
);
756 f
.serial(_TexScroll
[0], _TexScroll
[1]);
758 if (isAlternateTexEnabled())
760 f
.serialEnum(_AlternateOp
);
763 f
.serialPolyPtr(tex
);
764 _AlternateTexture2
= tex
;
768 tex
= _AlternateTexture2
;
769 f
.serialPolyPtr(tex
);
771 f
.serial(_TexScrollAlternate
[0], _TexScrollAlternate
[1]);
775 _AlternateTexture2
= 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
);
800 float normFactor
= tb
->getNormalizationFactor();
801 if (normFactor
== 0.f
) // have we computed the normalization factor ?
803 /// todo : caching of this value
805 normFactor
= tb
->getNormalizationFactor();
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())
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);
832 CTextureBump
*tb
= dynamic_cast<CTextureBump
*>((ITexture
*) _Texture2
);
835 float normFactor
= tb
->getNormalizationFactor();
836 if (normFactor
== 0.f
) // have we computed the normalization factor ?
838 /// todo : caching of this value
840 normFactor
= tb
->getNormalizationFactor();
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
);
859 if (_MainOp
!= EnvBumpMap
)
861 setupMultiTexEnv(_MainOp
, primary
, _Texture2
, mat
, *driver
);
862 _MultiTexState
&= ~(uint8
) EnvBumpMapUsed
;
863 _MultiTexState
&= ~(uint8
) AlternateTextureUsed
;
867 if (!_ForceBasicCaps
&& (driver
->supportTextureAddrMode(CMaterial::OffsetTexture
) || driver
->supportEMBM())) // envbumpmap supported ?
869 CTextureBump
*tb
= dynamic_cast<CTextureBump
*>((ITexture
*) _Texture2
);
872 float normFactor
= tb
->getNormalizationFactor();
873 if (normFactor
== 0.f
) // have we computed the normalization factor ?
875 /// todo : caching of this value
877 normFactor
= tb
->getNormalizationFactor();
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
);
894 mat
.setTexture(0, primary
);
895 mat
.texEnvOpRGB(0, CMaterial::Modulate
);
897 _MultiTexState
&= ~(uint8
) EnvBumpMapUsed
;
901 updateTexWrapMode(*driver
);
905 //=======================================
906 void CPSMultiTexturedParticle::setupMultiTexEnv(TOperator op
, ITexture
*tex1
, ITexture
*tex2
, CMaterial
&mat
, IDriver
&drv
)
908 NL_PS_FUNC(CPSMultiTexturedParticle_setupMultiTexEnv
)
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);
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);
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
);
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
);
980 mat
.setTexture(0, tex1
);
981 mat
.texEnvOpRGB(0, CMaterial::Replace
);
982 mat
.setTexture(1, NULL
);
983 mat
.enableTexAddrMode(false);
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);
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
);
1010 // retrieve the heightmap from the bumpmap
1011 NLMISC::CSmartPtr
<ITexture
> hm
= bm
->getHeightMap();
1016 //=========================================
1017 void CPSMultiTexturedParticle::setTexture2Alternate(ITexture
*tex
)
1019 NL_PS_FUNC(CPSMultiTexturedParticle_setTexture2Alternate
)
1020 _AlternateTexture2
= tex
;
1021 if (_AlternateOp
!= EnvBumpMap
)
1023 ConvertFromBumpMap(_AlternateTexture2
);
1027 ConvertToBumpMap(_AlternateTexture2
);
1032 //==========================================
1033 void CPSMultiTexturedParticle::setTexture2(ITexture
*tex
)
1035 NL_PS_FUNC(CPSMultiTexturedParticle_setTexture2
)
1037 if (_MainOp
!= EnvBumpMap
)
1039 ConvertFromBumpMap(_Texture2
);
1043 if (!dynamic_cast<NL3D::CTextureBump
*>((ITexture
*) _Texture2
))
1045 ConvertToBumpMap(_Texture2
);
1051 //==========================================
1052 void CPSMultiTexturedParticle::setMainTexOp(TOperator op
)
1054 NL_PS_FUNC(CPSMultiTexturedParticle_setMainTexOp
)
1056 if (_MainOp
== EnvBumpMap
)
1058 ConvertToBumpMap(_Texture2
);
1062 ConvertFromBumpMap(_Texture2
);
1067 //==========================================
1068 void CPSMultiTexturedParticle::setAlternateTexOp(TOperator op
)
1070 NL_PS_FUNC(CPSMultiTexturedParticle_setAlternateTexOp
)
1072 if (_AlternateOp
== EnvBumpMap
)
1074 ConvertToBumpMap(_AlternateTexture2
);
1078 ConvertFromBumpMap(_AlternateTexture2
);
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
)
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
);
1128 if (_AlternateTexture2
) dest
.push_back(_AlternateTexture2
);
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());