# 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  

vegetable.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/vegetable.h"
00029 #include "nel/misc/common.h"
00030 #include "3d/vegetable_manager.h"
00031 #include "3d/fast_floor.h"
00032 
00033 
00034 using namespace std;
00035 using namespace NLMISC;
00036 
00037 
00038 namespace NL3D 
00039 {
00040 
00041 
00042 // ***************************************************************************
00043 // Generate random value, but seed is spacial. Take a high frequency, so it gets more the aspect of random.
00044 static  CNoiseValue             RandomGenerator(0,1, 7.68f);
00045 
00046 
00047 // ***************************************************************************
00048 CVegetable::CVegetable()
00049 {
00050         // Ground style density.
00051         setAngleGround(0);
00052 
00053         // Density not maximised.
00054         MaxDensity= -1;
00055 
00056         // No scale.
00057         Sxy.Abs= Sz.Abs= 1;
00058         Sxy.Rand= Sz.Rand= 0;
00059         // No rotation.
00060         Rx.Abs= Ry.Abs= Rz.Abs= 0;
00061         Rx.Rand= Ry.Rand= Rz.Rand= 0;
00062         // No BendFactor.
00063         BendFactor.Abs= 1;
00064         BendFactor.Rand= 0;
00065         BendFrequencyFactor= 1;
00066 
00067         // Appear at 0.
00068         DistType= 0;
00069 
00070         _Manager= NULL;
00071 }
00072 
00073 
00074 // ***************************************************************************
00075 void    CVegetable::setAngleGround(float cosAngleMin)
00076 {
00077         _AngleType= AngleGround;
00078 
00079         _CosAngleMin= cosAngleMin;
00080         // We must be at densityFactor==1, when cosAngle==1, keeping the same formula.
00081         _CosAngleMax= 1 + (1-cosAngleMin);
00082 
00083         // precalc
00084         _CosAngleMiddle= (_CosAngleMin + _CosAngleMax)/2;
00085         _OOCosAngleDist= _CosAngleMax - _CosAngleMiddle;
00086         if(_OOCosAngleDist)
00087                 _OOCosAngleDist= 1.0f / _OOCosAngleDist;
00088 }
00089 
00090 // ***************************************************************************
00091 void    CVegetable::setAngleCeiling(float cosAngleMax)
00092 {
00093         _AngleType= AngleCeiling;
00094 
00095         _CosAngleMax= cosAngleMax;
00096         // We must be at densityFactor==1, when cosAngle==-1, keeping the same formula.
00097         _CosAngleMin= -1 - (cosAngleMax-(-1));
00098         
00099         // precalc
00100         _CosAngleMiddle= (_CosAngleMin + _CosAngleMax)/2;
00101         _OOCosAngleDist= _CosAngleMax - _CosAngleMiddle;
00102         if(_OOCosAngleDist)
00103                 _OOCosAngleDist= 1.0f / _OOCosAngleDist;
00104 }
00105 
00106 // ***************************************************************************
00107 void    CVegetable::setAngleWall(float cosAngleMin, float cosAngleMax)
00108 {
00109         _AngleType= AngleWall;
00110 
00111         _CosAngleMin= cosAngleMin;
00112         _CosAngleMax= cosAngleMax;
00113 
00114         // precalc
00115         _CosAngleMiddle= (_CosAngleMin + _CosAngleMax)/2;
00116         _OOCosAngleDist= _CosAngleMax - _CosAngleMiddle;
00117         if(_OOCosAngleDist)
00118                 _OOCosAngleDist= 1.0f / _OOCosAngleDist;
00119 }
00120 
00121 
00122 // ***************************************************************************
00123 void    CVegetable::registerToManager(CVegetableManager *manager)
00124 {
00125         nlassert(manager);
00126         _Manager= manager;
00127         _VegetableShape= _Manager->getVegetableShape(ShapeName);
00128 }
00129 
00130 
00131 // ***************************************************************************
00132 void    CVegetable::generateGroupEx(float nbInst, const CVector &posInWorld, const CVector &surfaceNormal, uint vegetSeed, std::vector<CVector2f> &instances) const
00133 {
00134 
00135         // Density modulation.
00136         //===================
00137 
00138         // compute cos of angle between surfaceNormal and K(0,0,1).
00139         float   cosAngle= surfaceNormal.z;
00140         // compute angleFactor density. Use a quadratic, because f'(_CosAngleMiddle)==0.
00141         float   angleFact= 1 - sqr((cosAngle - _CosAngleMiddle) * _OOCosAngleDist);
00142         angleFact= max(0.f, angleFact);
00143         // modulate density with angleFactor.
00144         nbInst*= angleFact;
00145 
00146         // Now, 0<=nbInst<+oo. If we have 0.1, it means that we have 10% chance to spawn an instance.
00147         // So add a "random" value (with help of a noise with High frequency)
00148         // if nbInst==0, we should never have any instance (which may arise if evalOneLevelRandom()==1).
00149         // hence the 0.99f* which ensure that we do nbInst+= [0..1[.
00150         nbInst+= 0.99f * RandomGenerator.evalOneLevelRandom(posInWorld);
00151 
00152         // and then get only the integral part.
00153         sint    nbInstances= OptFastFloor(nbInst);
00154         nbInstances= max(0, nbInstances);
00155 
00156         // resize the instances
00157         instances.resize(nbInstances);
00158 
00159         // Position generation.
00160         //===================
00161         // For now, generate them randomly.
00162         static CVector2f        dSeed(0.513f, 0.267f);  // random values.
00163         CVector                         seed= posInWorld;
00164         seed.z+= vegetSeed * 0.723f;    // 0.723f is a random value.
00165         for(sint i=0; i<nbInstances; i++)
00166         {
00167                 instances[i].x= RandomGenerator.evalOneLevelRandom(seed);
00168                 seed.x+= dSeed.x;
00169                 instances[i].y= RandomGenerator.evalOneLevelRandom(seed);
00170                 seed.y+= dSeed.y;
00171         }
00172 }
00173 
00174 
00175 // ***************************************************************************
00176 void    CVegetable::generateGroup(const CVector &posInWorld, const CVector &surfaceNormal, float area, uint vegetSeed, std::vector<CVector2f> &instances) const
00177 {
00178         // number of instances to generate
00179         float   dens= Density.eval(posInWorld);
00180         if(MaxDensity >= 0)
00181                 dens= min(dens, MaxDensity);
00182         float   nbInst= area * dens;
00183 
00184         // modulate by normal and generate them.
00185         generateGroupEx(nbInst, posInWorld, surfaceNormal, vegetSeed, instances);
00186 }
00187 
00188 
00189 // ***************************************************************************
00190 void    CVegetable::generateGroupBiLinear(const CVector &posInWorld, const CVector posInWorldBorder[4], const CVector &surfaceNormal, float area, uint vegetSeed, std::vector<CVector2f> &instances) const
00191 {
00192         sint    i;
00193         const   float evenDistribFact= 12.25f;          // an arbitrary value to have a higher frequency for random.
00194 
00195         // compute how many instances to generate on borders of the patch
00196         // ==================
00197         float   edgeDensity[4];
00198         for(i=0; i<4; i++)
00199         {
00200                 // Get number of instances generated on edges
00201                 edgeDensity[i]= area * Density.eval(posInWorldBorder[i]);
00202                 if(MaxDensity >= 0)
00203                         edgeDensity[i]= min(edgeDensity[i], area * MaxDensity);
00204                 edgeDensity[i]= max(0.f, edgeDensity[i]);
00205         }
00206         // Average on center of the patch for each direction.
00207         float   edgeDensityCenterX;
00208         float   edgeDensityCenterY;
00209         edgeDensityCenterX= 0.5f * (edgeDensity[0] + edgeDensity[1]);
00210         edgeDensityCenterY= 0.5f * (edgeDensity[2] + edgeDensity[3]);
00211 
00212         
00213         // Average for all the patch
00214         float   nbInstAverage= 0.5f * (edgeDensityCenterX + edgeDensityCenterY);
00215 
00216 
00217         // generate instances on the patch
00218         // ==================
00219         generateGroupEx(nbInstAverage, posInWorld, surfaceNormal, vegetSeed, instances);
00220 
00221 
00222 
00223         // move instances x/y to follow edge repartition
00224         // ==================
00225         // If on a direction, both edges are 0 density, then must do a special formula
00226         bool    middleX= edgeDensityCenterX<=1;
00227         bool    middleY= edgeDensityCenterY<=1;
00228         float   OOEdgeDCX=0.0;
00229         float   OOEdgeDCY=0.0;
00230         if(!middleX)    OOEdgeDCX= 1.0f / edgeDensityCenterX;
00231         if(!middleY)    OOEdgeDCY= 1.0f / edgeDensityCenterY;
00232         // for all instances
00233         for(i=0; i<(sint)instances.size(); i++)
00234         {
00235                 float           x= instances[i].x;
00236                 float           y= instances[i].y;
00237                 // a seed for random.
00238                 CVector         randSeed(x*evenDistribFact, y*evenDistribFact, 0);
00239 
00240                 // X change.
00241                 if(middleX)
00242                 {
00243                         // instances are grouped at middle. this is the bijection of easeInEaseOut
00244                         x= x+x - easeInEaseOut(x);
00245                         x= x+x - easeInEaseOut(x);
00246                         instances[i].x= x;
00247                 }
00248                 else
00249                 {
00250                         // Swap X, randomly. swap more on border
00251                         // evaluate the density in X direction we have at this point.
00252                         float   densX= edgeDensity[0]*(1-x) + edgeDensity[1]* x ;
00253                         // If on the side of the lowest density
00254                         if(densX < edgeDensityCenterX)
00255                         {
00256                                 // may swap the position 
00257                                 float   rdSwap= (densX * OOEdgeDCX );
00258                                 // (densX * OOEdgeDCX) E [0..1[. The more it is near 0, the more is has chance to be swapped.
00259                                 rdSwap+= RandomGenerator.evalOneLevelRandom( randSeed );
00260                                 if(rdSwap<1)
00261                                         instances[i].x= 1 - instances[i].x;
00262                         }
00263                 }
00264 
00265                 // Y change.
00266                 if(middleY)
00267                 {
00268                         // instances are grouped at middle. this is the bijection of easeInEaseOut
00269                         y= y+y - easeInEaseOut(y);
00270                         y= y+y - easeInEaseOut(y);
00271                         instances[i].y= y;
00272                 }
00273                 else
00274                 {
00275                         // Swap Y, randomly. swap more on border
00276                         // evaluate the density in Y direction we have at this point.
00277                         float   densY= edgeDensity[2]*(1-y) + edgeDensity[3]* y ;
00278                         // If on the side of the lowest density
00279                         if(densY < edgeDensityCenterY)
00280                         {
00281                                 // may swap the position 
00282                                 float   rdSwap= (densY * OOEdgeDCY);
00283                                 // (densY * OOEdgeDCY) E [0..1[. The more it is near 0, the more is has chance to be swapped.
00284                                 rdSwap+= RandomGenerator.evalOneLevelRandom( randSeed );
00285                                 if(rdSwap<1)
00286                                         instances[i].y= 1 - instances[i].y;
00287                         }
00288                 }
00289 
00290         }
00291 
00292 }
00293 
00294 
00295 // ***************************************************************************
00296 void    CVegetable::reserveIgAddInstances(CVegetableInstanceGroupReserve &vegetIgReserve, TVegetableWater vegetWaterState, uint numInstances) const
00297 {
00298         nlassert(_Manager);
00299 
00300         if (_VegetableShape)
00301                 _Manager->reserveIgAddInstances(vegetIgReserve, _VegetableShape, (CVegetableManager::TVegetableWater)vegetWaterState, numInstances);
00302 }
00303 
00304 
00305 // ***************************************************************************
00306 void    CVegetable::generateInstance(CVegetableInstanceGroup *ig, const NLMISC::CMatrix &posInWorld, 
00307                 const NLMISC::CRGBAF &modulateAmbientColor, const NLMISC::CRGBAF &modulateDiffuseColor, float blendDistMax,
00308                 TVegetableWater vegetWaterState, CVegetableUV8 dlmUV) const
00309 {
00310         nlassert(_Manager);
00311 
00312 
00313         CVector         seed= posInWorld.getPos();
00314 
00315         // Generate Matrix.
00316         // ===============
00317 
00318         // Generate a random Scale / Rotation matrix.
00319         CMatrix         randomMat;
00320         // setup rotation
00321         CVector         rot;
00322         rot.x= Rx.eval(seed);
00323         rot.y= Ry.eval(seed);
00324         rot.z= Rz.eval(seed);
00325         randomMat.setRot(rot, CMatrix::ZXY);
00326         // scale.
00327         if(Sxy.Abs!=0 || Sxy.Rand!=0 || Sz.Abs!=0 || Sz.Rand!=0)
00328         {
00329                 CVector         scale;
00330                 scale.x= scale.y= Sxy.eval(seed);
00331                 scale.z= Sz.eval(seed);
00332                 randomMat.scale(scale);
00333         }
00334 
00335         // Final Matrix.
00336         CMatrix         finalMatrix;
00337         finalMatrix= posInWorld * randomMat;
00338 
00339         // Generate Color and factor
00340         // ===============
00341         CRGBAF          materialColor(1,1,1,1);
00342         // evaluate gradients. If none, color not modified.
00343         Color.eval(seed, materialColor);
00344         // modulate with user
00345         CRGBAF          ambient, diffuse;
00346         ambient= modulateAmbientColor * materialColor;
00347         diffuse= modulateDiffuseColor * materialColor;
00348 
00349         // Generate a bendFactor
00350         float   bendFactor= BendFactor.eval(seed);
00351         // Generate a bendPhase
00352         float   bendPhase= BendPhase.eval(seed);
00353 
00354 
00355         // Append to the vegetableManager
00356         // ===============
00357         if (_VegetableShape)
00358         {
00359                 _Manager->addInstance(ig, _VegetableShape, finalMatrix, ambient, diffuse, 
00360                         bendFactor, bendPhase, BendFrequencyFactor, blendDistMax, 
00361                         (CVegetableManager::TVegetableWater)vegetWaterState, dlmUV);
00362         }
00363 }
00364 
00365 
00366 // ***************************************************************************
00367 void    CVegetable::serial(NLMISC::IStream &f)
00368 {
00369         /*
00370         Version 1:
00371                 - add BendFrequencyFactor
00372         Version 0:
00373                 - base version
00374         */
00375         sint    ver= f.serialVersion(1);
00376 
00377         f.serial(ShapeName);
00378         f.serial(Density);
00379         f.serial(MaxDensity);
00380         f.serial(_CosAngleMin, _CosAngleMax, _CosAngleMiddle, _OOCosAngleDist);
00381         f.serialEnum(_AngleType);
00382         f.serial(Sxy, Sz);
00383         f.serial(Rx, Ry, Rz);
00384         f.serial(BendFactor);
00385         f.serial(BendPhase);
00386         f.serial(Color);
00387         f.serial(DistType);
00388 
00389         if(ver>=1)
00390                 f.serial(BendFrequencyFactor);
00391         else
00392                 BendFrequencyFactor= 1;
00393 }
00394 
00395 
00396 } // NL3D