Model_prt.cpp (8808B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 #include "tr_local.h" 33 #include "Model_local.h" 34 35 static const char *parametricParticle_SnapshotName = "_ParametricParticle_Snapshot_"; 36 37 /* 38 ==================== 39 idRenderModelPrt::idRenderModelPrt 40 ==================== 41 */ 42 idRenderModelPrt::idRenderModelPrt() { 43 particleSystem = NULL; 44 } 45 46 /* 47 ==================== 48 idRenderModelPrt::InitFromFile 49 ==================== 50 */ 51 void idRenderModelPrt::InitFromFile( const char *fileName ) { 52 name = fileName; 53 particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, fileName ) ); 54 } 55 56 /* 57 ================= 58 idRenderModelPrt::TouchData 59 ================= 60 */ 61 void idRenderModelPrt::TouchData() { 62 // Ensure our particle system is added to the list of referenced decls 63 particleSystem = static_cast<const idDeclParticle *>( declManager->FindType( DECL_PARTICLE, name ) ); 64 } 65 66 /* 67 ==================== 68 idRenderModelPrt::InstantiateDynamicModel 69 ==================== 70 */ 71 idRenderModel *idRenderModelPrt::InstantiateDynamicModel( const struct renderEntity_s *renderEntity, const viewDef_t *viewDef, idRenderModel *cachedModel ) { 72 idRenderModelStatic *staticModel; 73 74 if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) { 75 delete cachedModel; 76 cachedModel = NULL; 77 } 78 79 // this may be triggered by a model trace or other non-view related source, to which we should look like an empty model 80 if ( renderEntity == NULL || viewDef == NULL ) { 81 delete cachedModel; 82 return NULL; 83 } 84 85 if ( r_skipParticles.GetBool() ) { 86 delete cachedModel; 87 return NULL; 88 } 89 90 /* 91 // if the entire system has faded out 92 if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && viewDef->renderView.time * 0.001f >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) { 93 delete cachedModel; 94 return NULL; 95 } 96 */ 97 98 if ( cachedModel != NULL ) { 99 100 assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL ); 101 assert( idStr::Icmp( cachedModel->Name(), parametricParticle_SnapshotName ) == 0 ); 102 103 staticModel = static_cast<idRenderModelStatic *>(cachedModel); 104 105 } else { 106 107 staticModel = new (TAG_MODEL) idRenderModelStatic; 108 staticModel->InitEmpty( parametricParticle_SnapshotName ); 109 } 110 111 particleGen_t g; 112 113 g.renderEnt = renderEntity; 114 g.renderView = &viewDef->renderView; 115 g.origin.Zero(); 116 g.axis.Identity(); 117 118 for ( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ ) { 119 idParticleStage *stage = particleSystem->stages[stageNum]; 120 121 if ( !stage->material ) { 122 continue; 123 } 124 if ( !stage->cycleMsec ) { 125 continue; 126 } 127 if ( stage->hidden ) { // just for gui particle editor use 128 staticModel->DeleteSurfaceWithId( stageNum ); 129 continue; 130 } 131 132 idRandom steppingRandom, steppingRandom2; 133 134 int stageAge = g.renderView->time[renderEntity->timeGroup] + renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] * 1000 - stage->timeOffset * 1000; 135 int stageCycle = stageAge / stage->cycleMsec; 136 137 // some particles will be in this cycle, some will be in the previous cycle 138 steppingRandom.SetSeed( (( stageCycle << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) ); 139 steppingRandom2.SetSeed( (( (stageCycle-1) << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) ); 140 141 int count = stage->totalParticles * stage->NumQuadsPerParticle(); 142 143 int surfaceNum; 144 modelSurface_t *surf; 145 146 if ( staticModel->FindSurfaceWithId( stageNum, surfaceNum ) ) { 147 surf = &staticModel->surfaces[surfaceNum]; 148 R_FreeStaticTriSurfVertexCaches( surf->geometry ); 149 } else { 150 surf = &staticModel->surfaces.Alloc(); 151 surf->id = stageNum; 152 surf->shader = stage->material; 153 surf->geometry = R_AllocStaticTriSurf(); 154 R_AllocStaticTriSurfVerts( surf->geometry, 4 * count ); 155 R_AllocStaticTriSurfIndexes( surf->geometry, 6 * count ); 156 } 157 158 int numVerts = 0; 159 idDrawVert *verts = surf->geometry->verts; 160 161 for ( int index = 0; index < stage->totalParticles; index++ ) { 162 g.index = index; 163 164 // bump the random 165 steppingRandom.RandomInt(); 166 steppingRandom2.RandomInt(); 167 168 // calculate local age for this index 169 int bunchOffset = stage->particleLife * 1000 * stage->spawnBunching * index / stage->totalParticles; 170 171 int particleAge = stageAge - bunchOffset; 172 int particleCycle = particleAge / stage->cycleMsec; 173 if ( particleCycle < 0 ) { 174 // before the particleSystem spawned 175 continue; 176 } 177 if ( stage->cycles && particleCycle >= stage->cycles ) { 178 // cycled systems will only run cycle times 179 continue; 180 } 181 182 if ( particleCycle == stageCycle ) { 183 g.random = steppingRandom; 184 } else { 185 g.random = steppingRandom2; 186 } 187 188 int inCycleTime = particleAge - particleCycle * stage->cycleMsec; 189 190 if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && 191 g.renderView->time[renderEntity->timeGroup] - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME]*1000 ) { 192 // don't fire any more particles 193 continue; 194 } 195 196 // supress particles before or after the age clamp 197 g.frac = (float)inCycleTime / ( stage->particleLife * 1000 ); 198 if ( g.frac < 0.0f ) { 199 // yet to be spawned 200 continue; 201 } 202 if ( g.frac > 1.0f ) { 203 // this particle is in the deadTime band 204 continue; 205 } 206 207 // this is needed so aimed particles can calculate origins at different times 208 g.originalRandom = g.random; 209 210 g.age = g.frac * stage->particleLife; 211 212 // if the particle doesn't get drawn because it is faded out or beyond a kill region, don't increment the verts 213 numVerts += stage->CreateParticle( &g, verts + numVerts ); 214 } 215 216 // numVerts must be a multiple of 4 217 assert( ( numVerts & 3 ) == 0 && numVerts <= 4 * count ); 218 219 // build the indexes 220 int numIndexes = 0; 221 triIndex_t *indexes = surf->geometry->indexes; 222 for ( int i = 0; i < numVerts; i += 4 ) { 223 indexes[numIndexes+0] = i+0; 224 indexes[numIndexes+1] = i+2; 225 indexes[numIndexes+2] = i+3; 226 indexes[numIndexes+3] = i+0; 227 indexes[numIndexes+4] = i+3; 228 indexes[numIndexes+5] = i+1; 229 numIndexes += 6; 230 } 231 232 surf->geometry->tangentsCalculated = false; 233 surf->geometry->numVerts = numVerts; 234 surf->geometry->numIndexes = numIndexes; 235 surf->geometry->bounds = stage->bounds; // just always draw the particles 236 } 237 238 return staticModel; 239 } 240 241 /* 242 ==================== 243 idRenderModelPrt::IsDynamicModel 244 ==================== 245 */ 246 dynamicModel_t idRenderModelPrt::IsDynamicModel() const { 247 return DM_CONTINUOUS; 248 } 249 250 /* 251 ==================== 252 idRenderModelPrt::Bounds 253 ==================== 254 */ 255 idBounds idRenderModelPrt::Bounds( const struct renderEntity_s *ent ) const { 256 return particleSystem->bounds; 257 } 258 259 /* 260 ==================== 261 idRenderModelPrt::DepthHack 262 ==================== 263 */ 264 float idRenderModelPrt::DepthHack() const { 265 return particleSystem->depthHack; 266 } 267 268 /* 269 ==================== 270 idRenderModelPrt::Memory 271 ==================== 272 */ 273 int idRenderModelPrt::Memory() const { 274 int total = 0; 275 276 total += idRenderModelStatic::Memory(); 277 278 if ( particleSystem ) { 279 total += sizeof( *particleSystem ); 280 281 for ( int i = 0; i < particleSystem->stages.Num(); i++ ) { 282 total += sizeof( particleSystem->stages[i] ); 283 } 284 } 285 286 return total; 287 }