00001 00007 /* Copyright, 2000 - 2002 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/particle_system_manager.h" 00029 #include "3d/particle_system_model.h" 00030 #include "3d/scene.h" 00031 #include "3d/skeleton_model.h" 00032 00033 00034 namespace NL3D { 00035 00036 00037 CParticleSystemManager::TManagerList &CParticleSystemManager::getManagerList() 00038 { 00039 static TManagerList *manager = NULL; 00040 if (manager == NULL) 00041 { 00042 manager = new TManagerList; 00043 } 00044 return *manager; 00045 } 00046 00047 00048 00049 00051 CParticleSystemManager::CParticleSystemManager() : _NumModels(0) 00052 { 00053 _CurrListIterator = _ModelList.end(); 00054 getManagerList().push_front(this); 00055 _GlobalListHandle = getManagerList().begin(); 00056 } 00057 00059 CParticleSystemManager::~CParticleSystemManager() 00060 { 00061 // remove from global list 00062 getManagerList().erase(_GlobalListHandle); 00063 } 00064 00066 void CParticleSystemManager::refreshModels(const std::vector<NLMISC::CPlane> &worldFrustumPyramid, const NLMISC::CVector &viewerPos) 00067 { 00068 #ifdef NL_DEBUG 00069 nlassert(_NumModels == _ModelList.size()); 00070 #endif 00071 00072 if (_NumModels == 0) return; 00073 const uint toProcess = std::min(_NumModels, (uint) NumProcessToRefresh); 00074 TModelList::iterator nextIt; 00075 for (uint k = 0; k < toProcess; ++k) 00076 { 00077 if (_CurrListIterator == _ModelList.end()) 00078 { 00079 _CurrListIterator = _ModelList.begin(); 00080 } 00081 nextIt = _CurrListIterator; 00082 ++ nextIt; 00083 (*_CurrListIterator)->refreshRscDeletion(worldFrustumPyramid, viewerPos); 00084 _CurrListIterator = nextIt; 00085 if (_NumModels == 0) break; 00086 } 00087 00088 #ifdef NL_DEBUG 00089 nlassert(_NumModels == _ModelList.size()); 00090 #endif 00091 } 00092 00094 CParticleSystemManager::TModelHandle CParticleSystemManager::addSystemModel(CParticleSystemModel *model) 00095 { 00096 #ifdef NL_DEBUG 00097 nlassert(std::find(_ModelList.begin(), _ModelList.end(), model) == _ModelList.end()); 00098 #endif 00099 _ModelList.push_front(model); 00100 ++_NumModels; 00101 00102 #ifdef NL_DEBUG 00103 nlassert(_NumModels == _ModelList.size()); 00104 #endif 00105 00106 TModelHandle handle; 00107 handle.Valid = true; 00108 handle.Iter = _ModelList.begin(); 00109 return handle; 00110 } 00111 00112 00114 void CParticleSystemManager::removeSystemModel(TModelHandle &handle) 00115 { 00116 nlassert(handle.Valid); 00117 #ifdef NL_DEBUG 00118 nlassert(_NumModels == _ModelList.size()); 00119 #endif 00120 nlassert(_NumModels != 0); 00121 if (handle.Iter == _CurrListIterator) 00122 { 00123 ++_CurrListIterator; 00124 } 00125 00126 _ModelList.erase(handle.Iter); 00127 --_NumModels; 00128 handle.Valid = false; 00129 #ifdef NL_DEBUG 00130 nlassert(_NumModels == _ModelList.size()); 00131 #endif 00132 } 00133 00134 00136 CParticleSystemManager::TAlwaysAnimatedModelHandle CParticleSystemManager::addPermanentlyAnimatedSystem(CParticleSystemModel *ps) 00137 { 00138 #ifdef NL_DEBUG 00139 for(TAlwaysAnimatedModelList::iterator it = _PermanentlyAnimatedModelList.begin(); it != _PermanentlyAnimatedModelList.end(); ++it) 00140 { 00141 nlassert(it->Model != ps); 00142 } 00143 #endif 00144 CAlwaysAnimatedPS aaps; 00145 aaps.Model = ps; 00146 aaps.HasAncestorSkeleton = false; // even if there's an ancestor skeleton yet, force the manager to recompute relative pos of the system when clipped 00147 _PermanentlyAnimatedModelList.push_front(aaps); 00148 00149 00150 TAlwaysAnimatedModelHandle handle; 00151 handle.Valid = true; 00152 handle.Iter = _PermanentlyAnimatedModelList.begin(); 00153 return handle; 00154 } 00155 00157 void CParticleSystemManager::removePermanentlyAnimatedSystem(CParticleSystemManager::TAlwaysAnimatedModelHandle &handle) 00158 { 00159 nlassert(handle.Valid); 00160 _PermanentlyAnimatedModelList.erase(handle.Iter); 00161 handle.Valid = false; 00162 } 00163 00165 void CParticleSystemManager::processAnimate(TAnimationTime deltaT) 00166 { 00167 for (TAlwaysAnimatedModelList::iterator it = _PermanentlyAnimatedModelList.begin(); it != _PermanentlyAnimatedModelList.end();) 00168 { 00169 CParticleSystemModel &psm = *(it->Model); 00170 CParticleSystem *ps = psm.getPS(); 00171 TAlwaysAnimatedModelList::iterator nextIt = it; 00172 nextIt++; 00173 if (ps) 00174 { 00175 // test if already auto-animated 00176 if (ps->getAnimType() != CParticleSystem::AnimAlways) 00177 { 00178 psm.invalidateAutoAnimatedHandle(); 00179 it = _PermanentlyAnimatedModelList.erase(it); 00180 continue; 00181 } 00182 // special case for sticked fxs : 00183 // When a fx is sticked as a son of a skeleton model, the skeleton matrix is not updated 00184 // when the skeleton is not visible (clipped) 00185 // This is a concern when fx generate trails because when the skeleton becomes visible again, 00186 // a trail will appear between the previous visible pos and the new visible pos 00187 // to solve this : 00188 // When the ancestor skeleton is visible, we backup the relative position to the ancestor skeleton. 00189 // - if it is not visible at start, we must evaluate the position of the stick point anyway 00190 // When the father skeleton is clipped, we use the relative position 00191 if (psm.getAncestorSkeletonModel()) 00192 { 00193 if(psm.getAncestorSkeletonModel()->getVisibility() != CHrcTrav::Hide) // matrix of ancestor is irrelevant if the system is hidden (because sticked to hidden parent for example) 00194 { 00195 if (!psm.isClipVisible()) // the system may not be visible because of clod 00196 { 00197 if (!it->IsRelMatrix) // relative matrix already computed ? 00198 { 00199 if (!it->HasAncestorSkeleton) 00200 { 00201 psm.forceCompute(); 00202 } 00203 it->OldAncestorMatOrRelPos = it->OldAncestorMatOrRelPos.inverted() * psm.getWorldMatrix(); 00204 it->IsRelMatrix = true; 00205 } 00206 psm.setWorldMatrix(psm.getAncestorSkeletonModel()->getWorldMatrix() * it->OldAncestorMatOrRelPos); 00207 } 00208 else 00209 { 00210 // backup ancestor position matrix relative to the ancestor skeleton 00211 it->HasAncestorSkeleton = true; 00212 it->OldAncestorMatOrRelPos = psm.getAncestorSkeletonModel()->getWorldMatrix(); 00213 it->IsRelMatrix = false; 00214 } 00215 } 00216 } 00217 psm.doAnimate(); 00218 if (!psm.getEditionMode()) 00219 { 00220 // test deletion condition (no more particle, no more particle and emitters) 00221 if (ps->isDestroyConditionVerified()) 00222 { 00223 psm.releaseRscAndInvalidate(); 00224 } 00225 } 00226 00227 } 00228 it = nextIt; 00229 } 00230 } 00231 00233 void CParticleSystemManager::stopSound() 00234 { 00235 for(TModelList::iterator it = _ModelList.begin(); it != _ModelList.end(); ++it) 00236 { 00237 CParticleSystemModel &psm = *(*it); 00238 CParticleSystem *ps = psm.getPS(); 00239 if (ps) 00240 { 00241 ps->stopSound(); 00242 } 00243 } 00244 } 00245 00247 void CParticleSystemManager::reactivateSound() 00248 { 00249 for(TModelList::iterator it = _ModelList.begin(); it != _ModelList.end(); ++it) 00250 { 00251 CParticleSystemModel &psm = *(*it); 00252 CParticleSystem *ps = psm.getPS(); 00253 if (ps) 00254 { 00255 ps->reactivateSound(); 00256 } 00257 } 00258 } 00259 00261 void CParticleSystemManager::stopSoundForAllManagers() 00262 { 00263 for(TManagerList::iterator it = getManagerList().begin(); it != getManagerList().end(); ++it) 00264 { 00265 nlassert(*it); 00266 (*it)->stopSound(); 00267 } 00268 } 00269 00271 void CParticleSystemManager::reactivateSoundForAllManagers() 00272 { 00273 for(TManagerList::iterator it = getManagerList().begin(); it != getManagerList().end(); ++it) 00274 { 00275 nlassert(*it); 00276 (*it)->reactivateSound(); 00277 } 00278 } 00279 00280 00281 00282 } // NL3D 00283 00284 00285 00286 00287 00288 00289 00290 00291 00292 00293 00294 00295 00296 00297 00298 00299 00300 00301 00302 00303