void R_DeriveFacePlanes( srfTriangles_t *tri ) { Plane * planes; if ( !tri->facePlanes ) { R_AllocStaticTriSurfPlanes( tri, tri->numIndices ); } planes = tri->facePlanes; for ( int i = 0; i < tri->numIndices; i+= 3, planes++ ) { int i1, i2, i3; Vec3 d1, d2, normal; Vec3 *v1, *v2, *v3; i1 = tri->indices[i + 0]; i2 = tri->indices[i + 1]; i3 = tri->indices[i + 2]; v1 = &tri->verts[i1].xyz; v2 = &tri->verts[i2].xyz; v3 = &tri->verts[i3].xyz; d1[0] = v2->x - v1->x; d1[1] = v2->y - v1->y; d1[2] = v2->z - v1->z; d2[0] = v3->x - v1->x; d2[1] = v3->y - v1->y; d2[2] = v3->z - v1->z; normal[0] = d2.y * d1.z - d2.z * d1.y; normal[1] = d2.z * d1.x - d2.x * d1.z; normal[2] = d2.x * d1.y - d2.y * d1.x; float sqrLength, invLength; sqrLength = normal.x * normal.x + normal.y * normal.y + normal.z * normal.z; invLength = idMath::RSqrt( sqrLength ); (*planes)[0] = normal[0] * invLength; (*planes)[1] = normal[1] * invLength; (*planes)[2] = normal[2] * invLength; planes->FitThroughPoint( *v1 ); } tri->facePlanesCalculated = true; }
/* ==================== idRenderModelPrt::InstantiateDynamicModel ==================== */ idRenderModel *idRenderModelPrt::InstantiateDynamicModel( const struct renderEntity_s *renderEntity, const struct viewDef_s *viewDef, idRenderModel *cachedModel ) { idRenderModelStatic *staticModel; if ( cachedModel && !r_useCachedDynamicModels.GetBool() ) { delete cachedModel; cachedModel = NULL; } // this may be triggered by a model trace or other non-view related source, to which we should look like an empty model if ( !renderEntity || !viewDef ) { delete cachedModel; return NULL; } else if ( r_skipParticles.GetBool() ) { delete cachedModel; return NULL; } /* // if the entire system has faded out if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && viewDef->renderView.time * 0.001f >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] ) { delete cachedModel; return NULL; } */ else if ( cachedModel ) { assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL ); assert( idStr::Icmp( cachedModel->Name(), parametricParticle_SnapshotName ) == 0 ); staticModel = static_cast<idRenderModelStatic *>(cachedModel); } else { staticModel = new idRenderModelStatic; staticModel->InitEmpty( parametricParticle_SnapshotName ); } particleGen_t g; g.renderEnt = renderEntity; g.renderView = &viewDef->renderView; g.origin.Zero(); g.axis.Identity(); for ( int stageNum = 0; stageNum < particleSystem->stages.Num(); stageNum++ ) { idParticleStage *stage = particleSystem->stages[stageNum]; if ( !stage->material || !stage->cycleMsec ) { continue; } else if ( stage->hidden ) { // just for gui particle editor use staticModel->DeleteSurfaceWithId( stageNum ); continue; } idRandom steppingRandom, steppingRandom2; const int stageAge = g.renderView->time + (renderEntity->shaderParms[SHADERPARM_TIMEOFFSET] - stage->timeOffset) * 1000; const int stageCycle = stageAge / stage->cycleMsec; // some particles will be in this cycle, some will be in the previous cycle steppingRandom.SetSeed ( (( stageCycle << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) ); steppingRandom2.SetSeed( (( (stageCycle-1) << 10 ) & idRandom::MAX_RAND) ^ (int)( renderEntity->shaderParms[SHADERPARM_DIVERSITY] * idRandom::MAX_RAND ) ); const int count = stage->totalParticles * stage->NumQuadsPerParticle(); int surfaceNum = 0; modelSurface_t *surf; if ( staticModel->FindSurfaceWithId( stageNum, surfaceNum ) ) { surf = &staticModel->surfaces[surfaceNum]; R_FreeStaticTriSurfVertexCaches( surf->geometry ); } else { surf = &staticModel->surfaces.Alloc(); surf->id = stageNum; surf->shader = stage->material; surf->geometry = R_AllocStaticTriSurf(); R_AllocStaticTriSurfVerts( surf->geometry, 4 * count ); R_AllocStaticTriSurfIndexes( surf->geometry, 6 * count ); R_AllocStaticTriSurfPlanes( surf->geometry, 6 * count ); } int numVerts = 0; idDrawVert *verts = surf->geometry->verts; for ( int index = 0; index < stage->totalParticles; index++ ) { g.index = index; // calculate local age for this index //const int bunchOffset = (index * 1000 * stage->particleLife * stage->spawnBunching) / stage->totalParticles; //const int particleAge = stageAge - bunchOffset const int particleAge = stageAge - ((index * 1000 * stage->particleLife * stage->spawnBunching) / stage->totalParticles); const int particleCycle = particleAge / stage->cycleMsec; // before the particleSystem has spawned or // cycled systems will only run cycle times if ( particleCycle < 0 || ( stage->cycles && particleCycle >= stage->cycles ) ) { continue; } const int inCycleTime = particleAge - particleCycle * stage->cycleMsec; if ( renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] && g.renderView->time - inCycleTime >= renderEntity->shaderParms[SHADERPARM_PARTICLE_STOPTIME] * 1000 ) { // don't fire any more particles continue; } // supress particles before or after the age clamp g.frac = (float)inCycleTime / ( stage->particleLife * 1000 ); if ( g.frac < 0.0f || g.frac > 1.0f) { // < 0.0f ; yet to be spawned // > 1.0f ; particle is in the deadTime band continue; } else { g.age = g.frac * stage->particleLife; } // bump the random steppingRandom.RandomInt(); steppingRandom2.RandomInt(); if ( particleCycle == stageCycle ) { g.random = steppingRandom; } else { g.random = steppingRandom2; } // this is needed so aimed particles can calculate origins at different times g.originalRandom = g.random; // if the particle doesn't get drawn because it is faded out or beyond a kill region, don't increment the verts numVerts += stage->CreateParticle( &g, verts + numVerts ); } // numVerts must be a multiple of 4 assert( ( numVerts & 3 ) == 0 && numVerts <= 4 * count ); // build the indexes int numIndexes = 0; glIndex_t *indexes = surf->geometry->indexes; for ( int i = 0; i < numVerts; i += 4 ) { indexes[numIndexes+0] = i; indexes[numIndexes+1] = i+2; indexes[numIndexes+2] = i+3; indexes[numIndexes+3] = i; indexes[numIndexes+4] = i+3; indexes[numIndexes+5] = i+1; numIndexes += 6; } surf->geometry->tangentsCalculated = false; surf->geometry->facePlanesCalculated = false; surf->geometry->numVerts = numVerts; surf->geometry->numIndexes = numIndexes; surf->geometry->bounds = stage->bounds; // just always draw the particles } return staticModel; }