DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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 }