# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

ps_particle_basic.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/ps_particle_basic.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/driver.h"
00031 #include "3d/texture_grouped.h"
00032 #include "3d/texture_bump.h"
00033 #include "3d/texture_mem.h"
00034 #include "3d/particle_system.h"
00035 
00036 
00037 
00038 namespace NL3D 
00039 {
00040 
00041 
00042 
00044 // CPSParticle implementation  //
00046 
00047 //=======================================
00048         CPSParticle::CPSParticle() : _DisableAutoLOD(false)
00049 {
00050 
00051 }
00052 
00053 //=======================================
00054 void CPSParticle::showTool()
00055 {
00056         PARTICLES_CHECK_MEM;
00057 
00058         CVector I = CVector::I;
00059         CVector J = CVector::J;
00060 
00061         const CVector tab[] = { 2 * J, I + J
00062                                                         , I + J, 2 * I + J
00063                                                         , 2 * I + J, I
00064                                                         , I,  2 * I - J
00065                                                         , 2 * I - J, - .5f * J
00066                                                         , - .5f * J, -2 * I - J
00067                                                         , -2 * I - J, - I
00068                                                         , - I, -2 * I + J
00069                                                         , -2 * I + J, - I + J
00070                                                         , - I + J, 2 * J
00071                                                 };
00072         const uint tabSize = sizeof(tab) / (2 * sizeof(CVector));
00073 
00074         const float sSize = 0.1f;
00075         displayIcon2d(tab, tabSize, sSize);
00076 
00077         PARTICLES_CHECK_MEM;
00078 }
00079 
00080 //=======================================
00081 void CPSParticle::computeSrcStep(uint32 &step, uint &numToProcess)
00082 {               
00083         nlassert(_Owner && _Owner->getOwner());
00084         const CParticleSystem &ps = *(_Owner->getOwner());
00085         if (_DisableAutoLOD || !ps.isAutoLODEnabled() || _Owner->getSize() == 0) // Should Auto-LOD be used ?
00086         {
00087                 step = (1 << 16);
00088                 numToProcess = _Owner->getSize();
00089         }
00090         else
00091         {
00092                 float oneMinusLODRatio = ps.getOneMinusCurrentLODRatio();
00093                 float LODRatio = 1.f - oneMinusLODRatio;  
00094                 if (LODRatio > ps.getAutoLODStartDistPercent())
00095                 {
00096                         float factor = (LODRatio - 1.f) / (ps.getAutoLODStartDistPercent() - 1.f);
00097                         NLMISC::clamp(factor, 0.f, 1.f);
00098                         float r = factor;
00099                         for (uint k = 0; k < ps.getAutoLODDegradationExponent(); ++k)
00100                         {
00101                                 r *= factor;
00102                         }
00103                         numToProcess = (uint) (_Owner->getSize() * r);
00104                         if (numToProcess < 1) { numToProcess = 1; }
00105 
00106                         step =   ps.getAutoLODMode() ?                             // skip or limit number, depending on the mode
00107                                 (_Owner->getSize() << 16) / numToProcess : // skip particles
00108                                 (1<<16);                                                           // just display less particles
00109                 }
00110                 else
00111                 {
00112                         step = (1 << 16);
00113                         numToProcess = _Owner->getSize();
00114                 }
00115         }
00116 
00117 }
00118 
00120 // coloured particle implementation //
00122 
00123 //=======================================
00124 void CPSColoredParticle::setColorScheme(CPSAttribMaker<CRGBA> *col)
00125 {       
00126         nlassert(col);
00127         delete _ColorScheme;            
00128         _ColorScheme = col;
00129         if (getColorOwner() && col->hasMemory()) col->resize(getColorOwner()->getMaxSize(), getColorOwner()->getSize());
00130         updateMatAndVbForColor();
00131 }
00132 
00133 //=======================================
00134 void CPSColoredParticle::setColor(NLMISC::CRGBA col)
00135 {       
00136         delete _ColorScheme;
00137         _ColorScheme = NULL;
00138         _Color = col;
00139         updateMatAndVbForColor();
00140 }
00141 
00142 //=======================================
00143 CPSColoredParticle::CPSColoredParticle() : _Color(CRGBA(255, 255, 255)), _ColorScheme(NULL)
00144 {       
00145 }
00146 
00147 //=======================================
00148 CPSColoredParticle::~CPSColoredParticle()
00149 {       
00150         delete _ColorScheme;    
00151 }
00152 
00153 //=======================================
00154 void CPSColoredParticle::serialColorScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
00155 {       
00156         f.serialVersion(1);     
00157         if (f.isReading())
00158         {
00159                 if (_ColorScheme)
00160                 {
00161                         delete _ColorScheme;
00162                         _ColorScheme = NULL;
00163                 }
00164         }
00165         bool useColorScheme = _ColorScheme != NULL;
00166         f.serial(useColorScheme);
00167         if (useColorScheme)
00168         {
00169                 f.serialPolyPtr(_ColorScheme);
00170         }
00171         else
00172         {
00173                 f.serial(_Color);
00174         }
00175 }
00176 
00178 // sized particle implementation //
00180 
00181 //=======================================
00182 void CPSSizedParticle::setSizeScheme(CPSAttribMaker<float> *size)
00183 {       
00184         nlassert(size != NULL);
00185         delete _SizeScheme;     
00186         _SizeScheme = size;
00187         if (getSizeOwner() && size->hasMemory()) size->resize(getSizeOwner()->getMaxSize(), getSizeOwner()->getSize());
00188 }
00189 
00190 //=======================================
00191 void CPSSizedParticle::setSize(float size)
00192 {       
00193         delete _SizeScheme;
00194         _SizeScheme = NULL;     
00195         _ParticleSize = size;
00196 }
00197 
00198 //=======================================
00199 CPSSizedParticle::CPSSizedParticle() : _ParticleSize(0.3f), _SizeScheme(NULL)
00200 {
00201 }
00202 
00203 //=======================================
00204 CPSSizedParticle::~CPSSizedParticle()
00205 {       
00206         delete _SizeScheme;     
00207 }
00208 
00209 //=======================================
00210 void CPSSizedParticle::serialSizeScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
00211 {
00212         f.serialVersion(1);     
00213         if (f.isReading())
00214         {
00215                 if (_SizeScheme)
00216                 {
00217                         delete _SizeScheme;
00218                         _SizeScheme = NULL;
00219                 }
00220         }
00221         bool useSizeScheme = _SizeScheme != NULL;
00222         f.serial(useSizeScheme);
00223         if (useSizeScheme)
00224         {               
00225                 f.serialPolyPtr(_SizeScheme);
00226         }
00227         else
00228         {
00229                 f.serial(_ParticleSize);
00230         }       
00231 };
00232 
00234 // rotated particle implementation //
00236 
00237 float CPSRotated2DParticle::_RotTable[256 * 4];
00238 bool CPSRotated2DParticle::_InitializedRotTab = false;
00239 
00241 void CPSRotated2DParticle::setAngle2DScheme(CPSAttribMaker<float> *angle2DScheme)
00242 {
00243         nlassert(angle2DScheme);
00244         delete _Angle2DScheme;  
00245         _Angle2DScheme = angle2DScheme;
00246         if (getAngle2DOwner() && angle2DScheme->hasMemory()) angle2DScheme->resize(getAngle2DOwner()->getMaxSize(), getAngle2DOwner()->getSize());
00247 }
00248 
00250 void CPSRotated2DParticle::setAngle2D(float angle2DScheme)
00251 {       
00252         delete _Angle2DScheme;
00253         _Angle2DScheme = NULL;  
00254         _Angle2D = angle2DScheme;
00255 }
00256 
00258 CPSRotated2DParticle::CPSRotated2DParticle() : _Angle2D(0), _Angle2DScheme(NULL)
00259 {
00260 }
00261 
00263 CPSRotated2DParticle::~CPSRotated2DParticle()
00264 {       
00265         delete _Angle2DScheme;  
00266 }
00267 
00269 void CPSRotated2DParticle::serialAngle2DScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
00270 {
00271         f.serialVersion(1);     
00272         if (f.isReading())
00273         {
00274                 if (_Angle2DScheme)
00275                 {
00276                         delete _Angle2DScheme;
00277                         _Angle2DScheme = NULL;
00278                 }
00279         }
00280         bool useAngle2DScheme = _Angle2DScheme != NULL;
00281         f.serial(useAngle2DScheme);
00282         if (useAngle2DScheme)
00283         {
00284                 f.serialPolyPtr(_Angle2DScheme);
00285         }
00286         else
00287         {               
00288                 f.serial(_Angle2D);
00289         }       
00290 }
00291 
00293 void CPSRotated2DParticle::initRotTable(void)
00294 {
00295         float *ptFloat = _RotTable;
00296         for (uint32 k = 0; k < 256; ++k)
00297         {
00298                 const float ca = (float) cos(k * (1.0f / 256.0f) * 2.0f * NLMISC::Pi);
00299                 const float sa = (float) sin(k * (1.0f / 256.0f) * 2.0f * NLMISC::Pi);
00300 
00301                 *ptFloat++ = -ca - sa;
00302                 *ptFloat++ = -sa + ca;
00303 
00304                 *ptFloat++ = ca - sa;
00305                 *ptFloat++ = sa + ca;
00306         }
00307         _InitializedRotTab = true;
00308 }
00309 
00311 // textured particle implementation //
00313 
00315 void CPSTexturedParticle::setTextureIndexScheme(CPSAttribMaker<sint32> *animOrder)
00316 {
00317         nlassert(animOrder);
00318         nlassert(_TexGroup); // setTextureGroup must have been called before this       
00319         delete _TextureIndexScheme;             
00320         _TextureIndexScheme = animOrder;
00321         if (getTextureIndexOwner() && animOrder->hasMemory()) animOrder->resize(getTextureIndexOwner()->getMaxSize(), getTextureIndexOwner()->getSize());
00322 
00323 
00324         updateMatAndVbForTexture();
00325 }
00326 
00328 void CPSTexturedParticle::setTextureIndex(sint32 index)
00329 {       
00330         delete _TextureIndexScheme;     
00331         _TextureIndexScheme = NULL;     
00332         _TextureIndex = index;
00333 }
00334 
00336 void CPSTexturedParticle::setTextureGroup(NLMISC::CSmartPtr<CTextureGrouped> texGroup)
00337 {
00338         nlassert(texGroup);
00339         if (_Tex)
00340         {
00341                 _Tex = NULL;
00342         }
00343         _TexGroup = texGroup;
00344 }
00345 
00347 void CPSTexturedParticle::setTexture(CSmartPtr<ITexture> tex)
00348 {       
00349         delete _TextureIndexScheme;
00350         _TextureIndexScheme = NULL;     
00351         _Tex = tex;
00352         _TexGroup = NULL; // release any grouped texture if one was set before
00353         updateMatAndVbForTexture();
00354 }
00355 
00357 CPSTexturedParticle::CPSTexturedParticle() : _TexGroup(NULL),
00358                                                                                          _TextureIndexScheme(NULL),
00359                                                                                          _TextureIndex(0)
00360 {
00361 }
00362 
00364 CPSTexturedParticle::~CPSTexturedParticle()
00365 {       
00366         delete _TextureIndexScheme;     
00367 }
00368 
00370 void CPSTexturedParticle::serialTextureScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
00371 {
00372         f.serialVersion(1);     
00373         if (f.isReading())
00374         {
00375                 if (_TextureIndexScheme)
00376                 {
00377                         delete _TextureIndexScheme;
00378                         _TextureIndexScheme = NULL;                     
00379                         _Tex = NULL;
00380                         _TexGroup = NULL;
00381                 }
00382         }
00383 
00384         bool useAnimatedTexture;        
00385         if (!f.isReading())
00386         {
00387                 useAnimatedTexture = (_TexGroup != NULL);
00388         }
00389         f.serial(useAnimatedTexture);
00390         if (useAnimatedTexture)
00391         {
00392                 if (f.isReading())
00393                 {
00394                         CTextureGrouped *ptTex = NULL;
00395                         f.serialPolyPtr(ptTex);
00396                         _TexGroup = ptTex;
00397                 }
00398                 else
00399                 {
00400                         CTextureGrouped *ptTex = _TexGroup;
00401                         f.serialPolyPtr(ptTex);
00402                 }
00403                 
00404                 bool useTextureIndexScheme = _TextureIndexScheme != NULL;               
00405                 f.serial(useTextureIndexScheme);
00406                 if (useTextureIndexScheme)
00407                 {
00408                         f.serialPolyPtr(_TextureIndexScheme);
00409                         _TextureIndex = 0;                      
00410                 }
00411                 else
00412                 {                       
00413                         f.serial(_TextureIndex);
00414                 }
00415         }
00416         else
00417         {
00418                 if (f.isReading())
00419                 {
00420                         ITexture *ptTex = NULL;
00421                         f.serialPolyPtr(ptTex);
00422                         _Tex = ptTex;
00423                 }
00424                 else
00425                 {
00426                         ITexture *ptTex = _Tex;
00427                         f.serialPolyPtr(ptTex);
00428                 }
00429         }       
00430 }
00431 
00433 //       CPSRotated3DPlaneParticle  implementation    //
00435 
00437 void CPSRotated3DPlaneParticle::setPlaneBasisScheme(CPSAttribMaker<CPlaneBasis> *basisMaker)
00438 {
00439         nlassert(basisMaker);
00440         delete _PlaneBasisScheme;       
00441         _PlaneBasisScheme = basisMaker;
00442         if (getPlaneBasisOwner() && basisMaker->hasMemory()) basisMaker->resize(getPlaneBasisOwner()->getMaxSize(), getPlaneBasisOwner()->getSize());
00443 }
00444 
00446 void CPSRotated3DPlaneParticle::setPlaneBasis(const CPlaneBasis &basis)
00447 {       
00448         delete _PlaneBasisScheme;               
00449         _PlaneBasisScheme = NULL;       
00450         _PlaneBasis = basis;
00451 }
00452 
00454 CPSRotated3DPlaneParticle::CPSRotated3DPlaneParticle() : _PlaneBasisScheme(NULL)                                                                                                                
00455 {
00456         _PlaneBasis.X = CVector::I;
00457         _PlaneBasis.Y = CVector::J;
00458 }
00459 
00461 CPSRotated3DPlaneParticle::~CPSRotated3DPlaneParticle()
00462 {       
00463         delete _PlaneBasisScheme;       
00464 }
00465 
00467 void CPSRotated3DPlaneParticle::serialPlaneBasisScheme(NLMISC::IStream &f) throw(NLMISC::EStream)
00468 {
00469         f.serialVersion(1);     
00470         f.serialPolyPtr(_PlaneBasisScheme);     
00471         bool usePlaneBasisScheme = _PlaneBasisScheme != NULL;   
00472         if (!usePlaneBasisScheme)
00473         {
00474                 f.serial(_PlaneBasis);
00475         }
00476 }
00477 
00479 // CPSMaterial implementation //
00481 
00483 CPSMaterial::CPSMaterial()
00484 {
00485         _Mat.setBlend(true);
00486         _Mat.setBlendFunc(CMaterial::one, CMaterial::one);
00487         _Mat.setZWrite(false);  
00488 }
00489 
00491 void CPSMaterial::serialMaterial(NLMISC::IStream &f) throw(NLMISC::EStream)
00492 {
00493         f.serialVersion(1);     
00494         TBlendingMode m = getBlendingMode();
00495         f.serialEnum(m);
00496         setBlendingMode(m);     
00497 }
00498 
00500 void CPSMaterial::setBlendingMode(CPSMaterial::TBlendingMode mode)
00501 {
00502         switch (mode)
00503         {               
00504                 case add:
00505                         _Mat.setBlend(true);
00506                         _Mat.setBlendFunc(CMaterial::one, CMaterial::one);
00507                         _Mat.setZWrite(false);
00508                         _Mat.setAlphaTest(false);
00509                 break;
00510                 case modulate:
00511                         _Mat.setBlend(true);
00512                         _Mat.setBlendFunc(CMaterial::zero, CMaterial::srccolor);
00513                         _Mat.setZWrite(false);
00514                         _Mat.setAlphaTest(false);
00515                 break;
00516                 case alphaBlend:
00517                         _Mat.setBlend(true);
00518                         _Mat.setBlendFunc(CMaterial::srcalpha, CMaterial::invsrcalpha);
00519                         _Mat.setZWrite(false);
00520                         _Mat.setAlphaTest(false);
00521                 break;
00522                 case alphaTest:
00523                         _Mat.setBlend(false);
00524                         _Mat.setZWrite(true);
00525                         _Mat.setAlphaTest(true);
00526                 break;
00527         }
00528 }
00529 
00531 CPSMaterial::TBlendingMode CPSMaterial::getBlendingMode(void) const
00532 {
00533         if (_Mat.getBlend())
00534         {
00535                 CMaterial::TBlend srcBlend = _Mat.getSrcBlend();        
00536                 CMaterial::TBlend destBlend = _Mat.getDstBlend();
00537 
00538                 if (srcBlend == CMaterial::one && destBlend == CMaterial::one) return add;
00539                 if (srcBlend == CMaterial::zero && destBlend == CMaterial::srccolor) return modulate;
00540                 if (srcBlend == CMaterial::srcalpha && destBlend == CMaterial::invsrcalpha) return alphaBlend;
00541 
00542                 // unrecognized mode
00543                 nlassert(0);
00544                 return alphaTest; // to avoid a warning only ...
00545         }
00546         else
00547         {
00548                 return alphaTest;
00549         }
00550 }
00551 
00553 void CPSMaterial::forceModulateConstantColor(bool force, const NLMISC::CRGBA &col)
00554 {
00555         if (force)
00556         {
00558                 _Mat.texConstantColor(1, col);
00559                 _Mat.texEnvOpRGB(1, CMaterial::Modulate);
00560                 _Mat.texEnvOpAlpha(1, CMaterial::Modulate);
00561                 _Mat.texEnvArg0RGB(1, CMaterial::Previous, CMaterial::SrcColor);
00562                 _Mat.texEnvArg1RGB(1, CMaterial::Constant, CMaterial::SrcColor);
00563                 _Mat.texEnvArg0Alpha(1, CMaterial::Previous, CMaterial::SrcAlpha);
00564                 _Mat.texEnvArg1Alpha(1, CMaterial::Constant, CMaterial::SrcAlpha);
00565                 forceTexturedMaterialStages(2);
00566         }
00567         else
00568         {               
00569                 if (_Mat.getTexture(1) != NULL)
00570                 {
00571                         _Mat.setTexture(1, NULL);
00572                 }
00573         }
00574 }
00575 
00576 
00578 void CPSMaterial::forceTexturedMaterialStages(uint numStages)
00579 {
00580         ITexture *blankTex = NULL;
00581         uint k;
00582         for (k = 0; k < numStages; ++k)
00583         {
00584                 if (_Mat.getTexture(k) == NULL)
00585                 {
00586                         if (!blankTex)
00587                         {
00588                                 blankTex = CTextureMem::Create1x1WhiteTex();
00589                         }
00590                         _Mat.setTexture(k, blankTex);
00591                 }
00592         }
00593         for (; k < IDRV_MAT_MAXTEXTURES; ++k)
00594         {
00595                 if (_Mat.getTexture(k) != NULL)
00596                 {
00597                         _Mat.setTexture(k, NULL);
00598                 }               
00599         }
00600 }
00601 
00602 
00604 // CPSMultiTexturedParticle implementation //
00606 
00607 //=======================================
00608 bool CPSMultiTexturedParticle::_ForceBasicCaps  = false;
00609 
00610 //=======================================
00611 CPSMultiTexturedParticle::CPSMultiTexturedParticle() : _MultiTexState(TouchFlag), _BumpFactor(1.f)
00612 {       
00613 }
00614 
00615 //=======================================
00616 void    CPSMultiTexturedParticle::enableMultiTexture(bool enabled /*= true*/)
00617 {
00618         if (isMultiTextureEnabled() == enabled) return;
00619         if (!enabled)
00620         {
00621                 _Texture2                  = NULL;
00622                 _AlternateTexture2 = NULL;
00623                 _MultiTexState = 0;
00624         }
00625         else
00626         {               
00627                 _MainOp = Modulate;
00628                 _TexScroll[0].set(0, 0);
00629                 _TexScroll[1].set(0, 0);
00630                 _MultiTexState = (uint8) MultiTextureEnabled;
00631         }
00632         touch();        
00633 }
00634 
00635 //=======================================
00636 void    CPSMultiTexturedParticle::enableAlternateTex(bool enabled /*= true*/)
00637 {       
00638         nlassert(isMultiTextureEnabled()); // multitexturing must have been enabled first
00639         if (enabled == isAlternateTexEnabled()) return;
00640 
00641         if (enabled)
00642         {
00643                 _TexScrollAlternate[0].set(0, 0);
00644                 _TexScrollAlternate[1].set(0, 0);
00645                 _AlternateOp = Modulate;
00646                 _MultiTexState |= (uint8) AlternateTextureEnabled;
00647         }
00648         else
00649         {
00650                 _Texture2 = NULL;
00651                 _MultiTexState &= ~(uint8) AlternateTextureEnabled;
00652         }
00653         touch();
00654 }
00655 
00656 //=======================================
00657 void    CPSMultiTexturedParticle::serialMultiTex(NLMISC::IStream &f) throw(NLMISC::EStream)
00658 {
00660         sint ver = f.serialVersion(1);
00661         f.serial(_MultiTexState);
00662         if (isMultiTextureEnabled())
00663         {
00664                 f.serialEnum(_MainOp);
00665                 if (_MainOp == EnvBumpMap && ver >= 1)
00666                 {
00667                         f.serial(_BumpFactor);
00668                 }
00669                 ITexture *tex = NULL;
00670                 if (f.isReading())
00671                 {
00672                         f.serialPolyPtr(tex);
00673                         _Texture2 = tex;
00674                 }
00675                 else
00676                 {
00677                         tex = _Texture2;
00678                         f.serialPolyPtr(tex);
00679                 }
00680                 f.serial(_TexScroll[0], _TexScroll[1]);
00681                 
00682                 if (isAlternateTexEnabled())
00683                 {
00684                         f.serialEnum(_AlternateOp);                     
00685                         if (f.isReading())
00686                         {
00687                                 f.serialPolyPtr(tex);
00688                                 _AlternateTexture2 = tex;
00689                         }
00690                         else
00691                         {
00692                                 tex = _AlternateTexture2;
00693                                 f.serialPolyPtr(tex);
00694                         }
00695                         f.serial(_TexScrollAlternate[0], _TexScrollAlternate[1]);
00696                 }
00697                 else
00698                 {
00699                         _AlternateTexture2 = NULL;
00700                 }
00701         }
00702         else
00703         {
00704                 if (f.isReading())
00705                 {
00706                         _Texture2                  = NULL;
00707                         _AlternateTexture2 = NULL;
00708                 }
00709         }       
00710 }
00711 
00712 //=======================================
00713 void CPSMultiTexturedParticle::setupMaterial(ITexture *primary, IDriver *driver, CMaterial &mat)
00714 {
00716         if (isMultiTextureEnabled() && _MainOp  == EnvBumpMap && driver->isTextureAddrModeSupported(CMaterial::OffsetTexture))
00717         {
00718                 CTextureBump *tb = dynamic_cast<CTextureBump *>((ITexture *) _Texture2);
00719                 if (tb != NULL)
00720                 {                                       
00721                         float normFactor = tb->getNormalizationFactor();
00722                         if (normFactor == 0.f) // have we computed the normalization factor ?
00723                         {
00725                                 tb->generate();
00726                                 normFactor = tb->getNormalizationFactor();
00727                                 tb->release();
00728                         }
00729                         const float bMat[] = { _BumpFactor * normFactor, 0.f, 0.f, _BumpFactor * normFactor};   
00730                         driver->setMatrix2DForTextureOffsetAddrMode(1, bMat);
00731                 }               
00732         }
00733 
00734         if (!isTouched() && areBasicCapsForcedLocal() == areBasicCapsForced()) return;
00735         if (!isMultiTextureEnabled())           
00736         {               
00737                 mat.setTexture(0, primary);
00738                 mat.texEnvOpRGB(0, CMaterial::Modulate);
00739                 mat.setTexture(1, NULL);
00740         }
00741         else
00742         {                               
00743                 if (_MainOp  != EnvBumpMap)
00744                 {                       
00745                         setupMultiTexEnv(_MainOp, primary, _Texture2, mat);
00746                         _MultiTexState &= ~(uint8) EnvBumpMapUsed;
00747                         _MultiTexState &= ~(uint8) AlternateTextureUsed;
00748                 }
00749                 else
00750                 {
00751                         if (!_ForceBasicCaps && driver->isTextureAddrModeSupported(CMaterial::OffsetTexture)) // envbumpmap supported ?
00752                         {
00753                                 CTextureBump *tb = dynamic_cast<CTextureBump *>((ITexture *) _Texture2);
00754                                 if (tb != NULL)
00755                                 {                                       
00756                                         float normFactor = tb->getNormalizationFactor();
00757                                         if (normFactor == 0.f) // have we computed the normalization factor ?
00758                                         {
00760                                                 tb->generate();
00761                                                 normFactor = tb->getNormalizationFactor();
00762                                                 tb->release();
00763                                         }                                       
00764                                         setupMultiTexEnv(_MainOp, primary, _Texture2, mat);     
00765                                 }
00766                                 _MultiTexState &= ~(uint8) AlternateTextureUsed;
00767                                 _MultiTexState |= (uint8) EnvBumpMapUsed;                               
00768                         }
00769                         else // switch to alternate
00770                         {
00771                                 if (isAlternateTexEnabled())
00772                                 {
00773                                         _MultiTexState |= (uint8) AlternateTextureUsed;
00774                                         setupMultiTexEnv(_AlternateOp, primary, _AlternateTexture2, mat);
00775                                         _MultiTexState &= ~(uint8) EnvBumpMapUsed;
00776                                 }
00777                                 else // display the texture as it
00778                                 {
00779                                         setupMultiTexEnv(Decal, primary, NULL, mat);
00780                                         _MultiTexState &= ~(uint8) AlternateTextureUsed;
00781                                         _MultiTexState &= ~(uint8) EnvBumpMapUsed;
00782                                 }
00783                         }
00784                 }
00785         }
00786         
00787         (areBasicCapsForced());
00788         unTouch();
00789 }
00790 
00791 //=======================================
00792 void    CPSMultiTexturedParticle::setupMultiTexEnv(TOperator op, ITexture *tex1, ITexture *tex2, CMaterial &mat)
00793 {
00794         switch (op)
00795         {
00796                 case Add:                       
00797                         mat.setTexture(0, tex1);
00798                         mat.setTexture(1, tex2);
00799                         mat.texEnvOpRGB(0, CMaterial::Modulate);
00800                         mat.texEnvOpRGB(1, CMaterial::Add);
00801                         mat.enableTexAddrMode(false);
00802                         break;
00803                 case Modulate:
00804                         mat.setTexture(0, tex1);
00805                         mat.setTexture(1, tex2);
00806                         mat.texEnvOpRGB(0, CMaterial::Modulate);
00807                         mat.texEnvOpRGB(1, CMaterial::Modulate);
00808                         mat.enableTexAddrMode(false);
00809                         break;
00810                 case EnvBumpMap:
00811                         mat.setTexture(0, tex2);
00812                         mat.setTexture(1, tex1);
00813                         mat.texEnvOpRGB(0, CMaterial::Replace);
00814                         mat.texEnvOpRGB(1, CMaterial::Modulate);
00815                         mat.enableTexAddrMode(true);
00816                         mat.setTexAddressingMode(0, CMaterial::FetchTexture);           
00817                         mat.setTexAddressingMode(1, CMaterial::OffsetTexture);
00818                         break;
00819                 case Decal:
00820                         mat.setTexture(0, tex1);
00821                         mat.texEnvOpRGB(0, CMaterial::Replace);
00822                         mat.setTexture(1, NULL);
00823                         mat.enableTexAddrMode(false);
00824                         break;
00825                 default: break;
00826         }
00827 }
00828 
00829 //=====static func to convert a texture to a bumpmap
00830 static void ConvertToBumpMap(NLMISC::CSmartPtr<ITexture> &ptr)
00831 {
00832         if (!dynamic_cast<CTextureBump *>( (ITexture *) ptr))
00833         {
00834                 // convert to a bumpmap
00835                 CTextureBump *tb = new CTextureBump;
00836                 tb->setAbsoluteOffsets();
00837                 tb->setHeightMap((ITexture *) ptr);
00838                 ptr = tb;
00839         }       
00840 }
00841 
00842 //=====static func to convert a bumpmap to a texture (its heightmap)
00843 static void ConvertFromBumpMap(NLMISC::CSmartPtr<ITexture> &ptr)
00844 {
00845         CTextureBump *bm = dynamic_cast<CTextureBump *>( (ITexture *) ptr);
00846         if (bm)
00847         {
00848                 // retrieve the heightmap from the bumpmap
00849                 NLMISC::CSmartPtr<ITexture> hm = bm->getHeightMap();            
00850                 ptr = hm;
00851         }
00852 }
00853 
00854 //=========================================
00855 void    CPSMultiTexturedParticle::setTexture2Alternate(ITexture *tex)
00856 { 
00857         _AlternateTexture2 = tex;
00858         if (_AlternateOp != EnvBumpMap)
00859         {               
00860                 ConvertFromBumpMap(_AlternateTexture2);
00861         }
00862         else
00863         {
00864                 ConvertToBumpMap(_AlternateTexture2);           
00865         }
00866         touch();
00867 }
00868 
00869 //==========================================
00870 void    CPSMultiTexturedParticle::setTexture2(ITexture *tex) 
00871 { 
00872         _Texture2 = tex;
00873         if (_MainOp != EnvBumpMap)
00874         {               
00875                 ConvertFromBumpMap(_Texture2);
00876         }
00877         else
00878         {
00879                 if (!dynamic_cast<NL3D::CTextureBump *>((ITexture *) _Texture2))
00880                 {
00881                         ConvertToBumpMap(_Texture2);
00882                 }
00883         }
00884         touch();
00885 }
00886 
00887 //==========================================
00888 void    CPSMultiTexturedParticle::setMainTexOp(TOperator op)
00889 { 
00890         _MainOp = op;
00891         if (_MainOp == EnvBumpMap)
00892         {
00893                 ConvertToBumpMap(_Texture2);
00894         }
00895         else
00896         {
00897                 ConvertFromBumpMap(_Texture2);
00898         }
00899         touch();
00900 }
00901 
00902 //==========================================
00903 void    CPSMultiTexturedParticle::setAlternateTexOp(TOperator op)
00904 { 
00905         _AlternateOp = op;
00906         if (_AlternateOp == EnvBumpMap)
00907         {
00908                 ConvertToBumpMap(_AlternateTexture2);
00909         }
00910         else
00911         {
00912                 ConvertFromBumpMap(_AlternateTexture2);
00913         }
00914         touch();
00915 }
00916 
00917 
00918 
00919 //==========================================
00920 void    CPSMultiTexturedParticle::setUseLocalDate(bool use)
00921 {
00922         if (use) _MultiTexState |= ScrollUseLocalDate;
00923         else _MultiTexState &= ~ ScrollUseLocalDate;
00924 }
00925 
00926 
00927 //==========================================
00928 void    CPSMultiTexturedParticle::setUseLocalDateAlt(bool use)
00929 {
00930         if (use) _MultiTexState |= ScrollUseLocalDateAlternate;
00931         else _MultiTexState &= ~ ScrollUseLocalDateAlternate;
00932 }
00933 
00934 } // NL3D
00935 
00936 
00937 
00938 
00939