# 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  

flare_model.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000, 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/flare_model.h"
00029 #include "3d/flare_shape.h"
00030 #include "3d/driver.h"
00031 #include "3d/material.h"
00032 #include "3d/dru.h"
00033 #include "3d/scene.h"
00034 #include "3d/render_trav.h"
00035 
00036 
00037 
00038 namespace NL3D {
00039 
00040 
00041 /*
00042  * Constructor
00043  */
00044 CFlareModel::CFlareModel() : _Intensity(0)
00045 {
00046         setTransparency(true);
00047         setOpacity(false);
00048 }
00049 
00050 void CFlareModel::registerBasic()
00051 {
00052         // register the model and his observers
00053         CMOT::registerModel(FlareModelClassId, TransformShapeId, CFlareModel::creator); 
00054         CMOT::registerObs(RenderTravId, FlareModelClassId, CFlareRenderObs::creator);   
00055 }
00056 
00057 
00058 
00059 
00060 void    CFlareRenderObs::traverse(IObs *caller)
00061 {                       
00062         CRenderTrav                     *trav = NLMISC::safe_cast<CRenderTrav *>(Trav);
00063         CFlareModel                     *m    = NLMISC::safe_cast<CFlareModel *>(Model);
00064         IDriver                         *drv  = trav->getDriver();
00065         if (trav->isCurrentPassOpaque()) return;
00066         
00067         
00068 
00069         // transform the flare on screen        
00070         const CVector           upt = HrcObs->WorldMatrix.getPos(); // unstransformed pos       
00071         const CVector   pt = trav->ViewMatrix * upt;
00072 
00073 
00074 
00075         if (pt.y <= trav->Near) 
00076         {               
00077                 return; // flare behind us
00078         }
00079 
00080         nlassert(m->Shape);
00081         CFlareShape *fs = NLMISC::safe_cast<CFlareShape *>((IShape *) m->Shape);
00082         
00083 
00084     if (pt.y > fs->getMaxViewDist()) 
00085         {               
00086                 return; // flare too far away
00087         }
00088 
00089         float distIntensity;
00090 
00091         if (fs->getFlareAtInfiniteDist())
00092         {
00093                 distIntensity   = 1.f;
00094         }
00095         else
00096         {       
00097                 // compute a color ratio for attenuation with distance
00098                 const float distRatio = pt.y / fs->getMaxViewDist();
00099                 distIntensity = distRatio > fs->getMaxViewDistRatio() ? 1.f - (distRatio - fs->getMaxViewDistRatio()) / (1.f - fs->getMaxViewDistRatio()) : 1.f;                
00100         }       
00101 
00102         // compute position on screen
00103         uint32 width, height;
00104         drv->getWindowSize(width, height);
00105         const float middleX = .5f * (trav->Left + trav->Right);
00106         const float middleZ = .5f * (trav->Bottom + trav->Top);
00107         const sint xPos = (width>>1) + (sint) (width * (((trav->Near * pt.x) / pt.y) - middleX) / (trav->Right - trav->Left));
00108         const sint yPos = (height>>1) - (sint) (height * (((trav->Near * pt.z) / pt.y) - middleZ) / (trav->Top - trav->Bottom));        
00109 
00110         // read z-buffer value at the pos we are
00111         static std::vector<float> v(1);
00112         NLMISC::CRect rect(xPos, height - yPos, 1, 1);
00113         drv->getZBufferPart(v, rect);
00114 
00115         // project in screen space
00116         const float z = (float) (1.0 - (1.0 / pt.y - 1.0 / trav->Far) / (1.0 /trav->Near - 1.0 / trav->Far));
00117         
00118 
00119         if (!v.size() || z > v[0]) // test against z-buffer
00120         {
00121                 float p = fs->getPersistence();
00122                 if (fs == 0)
00123                 {
00124                         m->_Intensity = 0;                      
00125                         return;
00126                 }
00127                 else
00128                 {
00129                         m->_Intensity -= 1.f / p * (float)m->_Scene->getEllapsedTime(); 
00130                         if (m->_Intensity < 0.f) 
00131                         {                               
00132                                 m->_Intensity = 0.f;
00133                                 return; // nothing to draw
00134                         }
00135                 }                       
00136         }
00137         else
00138         {
00139                 float p = fs->getPersistence();
00140                 if (fs == 0)
00141                 {
00142                         m->_Intensity = 1;
00143                 }
00144                 else
00145                 {
00146                         m->_Intensity += 1.f / p * (float)m->_Scene->getEllapsedTime(); 
00147                         if (m->_Intensity > 1.f) m->_Intensity = 1.f;
00148                 }                       
00149         }
00150 
00151         static CMaterial material;
00152         static CVertexBuffer vb; 
00153 
00154         static bool setupDone = false;
00155 
00156     
00157         if (!setupDone)
00158         {
00159                 material.setBlend(true);
00160                 material.setBlendFunc(CMaterial::one, CMaterial::one);
00161                 material.setZWrite(false);      
00162                 material.setZFunc(CMaterial::always);
00163                 material.setLighting(false);    
00164                 material.setDoubleSided(true);
00165 
00166                 // setup vertex buffer
00167                 vb.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag);
00168                 vb.setNumVertices(4);
00169                 vb.setTexCoord(0, 0, NLMISC::CUV(1, 0));
00170                 vb.setTexCoord(1, 0, NLMISC::CUV(1, 1));
00171                 vb.setTexCoord(2, 0, NLMISC::CUV(0, 1));
00172                 vb.setTexCoord(3, 0, NLMISC::CUV(0, 0));
00173 
00174                 setupDone = true;
00175         }
00176 
00177         
00178 
00179 
00180         // setup driver 
00181         drv->activeVertexProgram(NULL);
00182         drv->setupModelMatrix(CMatrix::Identity);
00183         drv->activeVertexBuffer(vb);
00184         
00185 
00186         // we don't change the fustrum to draw 2d shapes : it is costly, and we need to restore it after the drawing has been done
00187         // we setup Z to be (near + far) / 2, and setup x and y to get the screen coordinates we want
00188         const float zPos             = 0.5f * (trav->Near + trav->Far); 
00189         const float zPosDivNear      = zPos / trav->Near;
00190 
00191         // compute the coeeff so that x = ax * px + bx; y = ax * py + by
00192         const float aX = ( (trav->Right - trav->Left) / (float) width) * zPosDivNear;   
00193         const float bX = zPosDivNear * (middleX - 0.5f * (trav->Right - trav->Left));
00194         //
00195         const float aY = - ( (trav->Top - trav->Bottom) / (float) height) * zPosDivNear;        
00196         const float bY = zPosDivNear * (middleZ + 0.5f * (trav->Top - trav->Bottom));
00197 
00198         const CVector I = trav->CamMatrix.getI();
00199         const CVector J = trav->CamMatrix.getJ();
00200         const CVector K = trav->CamMatrix.getK();
00201         //
00202         CRGBA            col;   
00203         CRGBA        flareColor = fs->getColor(); 
00204         const float norm = sqrtf((float) (((xPos - (width>>1)) * (xPos - (width>>1)) + (yPos - (height>>1))*(yPos - (height>>1)))))
00205                                                    / (float) (width>>1);
00206 
00207         // check for dazzle and draw it
00208         if (fs->hasDazzle())
00209         {
00210                 if (norm < fs->getDazzleAttenuationRange())
00211                 {
00212                         float dazzleIntensity = 1.f - norm / fs->getDazzleAttenuationRange();
00213                         CRGBA dazzleColor = fs->getDazzleColor(); 
00214                         col.modulateFromui(dazzleColor, (uint) (255.f * m->_Intensity * dazzleIntensity));
00215                         material.setColor(col);
00216                         material.setTexture(0, NULL);
00217         
00218                         const CVector dazzleCenter = trav->CamPos + zPos * J;
00219                         const CVector dI = (width>>1) * aX * I;
00220                         const CVector dK = (height>>1) * bX * K;
00221 
00222                         vb.setVertexCoord(0, dazzleCenter + dI + dK);
00223                         vb.setVertexCoord(1, dazzleCenter + dI - dK);
00224                         vb.setVertexCoord(2, dazzleCenter - dI - dK);
00225                         vb.setVertexCoord(3, dazzleCenter - dI + dK);
00226 
00227                         drv->renderQuads(material, 0, 1);
00228                 }
00229         }               
00230         if (!fs->getAttenuable() )
00231         {
00232                 col.modulateFromui(flareColor, (uint) (255.f * distIntensity * m->_Intensity));
00233         }
00234         else
00235         {
00236                 if (norm > fs->getAttenuationRange() || fs->getAttenuationRange() == 0.f) 
00237                 {                       
00238                         return; // nothing to draw;             
00239                 }
00240                 col.modulateFromui(flareColor, (uint) (255.f * distIntensity * m->_Intensity * (1.f - norm / fs->getAttenuationRange() )));
00241         }
00242 
00243 
00244         material.setColor(col); 
00245 
00246         CVector scrPos; // vector that will map to the center of the flare on scree
00247 
00248         // process each flare
00249         // delta for each new Pos 
00250         const float dX = fs->getFlareSpacing() * ((sint) (width >> 1) - xPos);
00251         const float dY = fs->getFlareSpacing() * ((sint) (height >> 1) - yPos);
00252 
00253         float size; // size of the current flare
00254 
00255         uint k = 0;
00256         ITexture *tex;
00257 
00258         if (fs->getFirstFlareKeepSize())
00259         {
00260                 tex = fs->getTexture(0);
00261                 if (tex)
00262                 {
00263                         size = fs->getSize(0);
00264 
00265                         vb.setVertexCoord(0, upt + size * (I + K) );
00266                         vb.setVertexCoord(1, upt + size * (I - K) );
00267                         vb.setVertexCoord(2, upt + size * (-I - K) );
00268                         vb.setVertexCoord(3, upt + size * (-I + K) );
00269 
00270 
00271                         material.setTexture(0, tex);
00272                         drv->renderQuads(material, 0, 1);                       
00273                         k = 1;
00274                 }               
00275         }
00276         else
00277         {
00278                 k = 0;
00279         }
00280 
00281         for (; k < MaxFlareNum; ++k)
00282         {
00283                 tex = fs->getTexture(k);
00284                 if (tex)
00285                 {
00286                         // compute vector that map to the center of the flare
00287 
00288                         scrPos = (aX * (xPos + dX * fs->getRelativePos(k)) + bX) * I 
00289                                      +  zPos * J + (aY * (yPos + dY * fs->getRelativePos(k)) + bY) * K + trav->CamMatrix.getPos(); 
00290 
00291 
00292                         
00293 
00294                         size = fs->getSize(k) / trav->Near;                     
00295                         vb.setVertexCoord(0, scrPos + size * (I + K) );
00296                         vb.setVertexCoord(1, scrPos + size * (I - K) );
00297                         vb.setVertexCoord(2, scrPos + size * (-I - K) );
00298                         vb.setVertexCoord(3, scrPos + size * (-I + K) );
00299                         material.setTexture(0, tex);
00300                         drv->renderQuads(material, 0, 1);               
00301                 }
00302                 
00303         }               
00304         this->traverseSons();
00305 }
00306 
00307 
00308 
00309 } // NL3D