/** * @brief Check rain particle visibility * @details Check the snowflake is visible and still going, wrapping if necessary. */ static qboolean CG_SnowParticleCheckVisible(cg_atmosphericParticle_t *particle) { float moved; vec2_t distance; if (!particle || particle->active == ACT_NOT) { return qfalse; } // units moved since last frame moved = (cg.time - cg_atmFx.lastRainTime) * 0.001; VectorMA(particle->pos, moved, particle->delta, particle->pos); if (particle->pos[2] < BG_GetSkyGroundHeightAtPoint(particle->pos)) { return CG_SetParticleActive(particle, ACT_NOT); } distance[0] = particle->pos[0] - cg.refdef_current->vieworg[0]; distance[1] = particle->pos[1] - cg.refdef_current->vieworg[1]; if ((distance[0] * distance[0] + distance[1] * distance[1]) > Square(MAX_ATMOSPHERIC_DISTANCE)) { // just nuke this particle, let it respawn return CG_SetParticleActive(particle, ACT_NOT); } return qtrue; }
static qboolean CG_SnowParticleCheckVisible(cg_atmosphericParticle_t *particle) { // Check the snowflake is visible and still going, wrapping if necessary. float moved; vec2_t distance; //int msec = trap_Milliseconds(); //n_checkvisibletime++; if (!particle || particle->active == ACT_NOT) { // checkvisibletime += trap_Milliseconds() - msec; return(qfalse); } moved = (cg.time - cg_atmFx.lastRainTime) * 0.001; // Units moved since last frame VectorMA(particle->pos, moved, particle->delta, particle->pos); if (particle->pos[2] < BG_GetSkyGroundHeightAtPoint(particle->pos)) { //checkvisibletime += trap_Milliseconds() - msec; return CG_SetParticleActive(particle, ACT_NOT); } distance[0] = particle->pos[0] - cg.refdef_current->vieworg[0]; distance[1] = particle->pos[1] - cg.refdef_current->vieworg[1]; if ((distance[0] * distance[0] + distance[1] * distance[1]) > Square(MAX_ATMOSPHERIC_DISTANCE)) { // just nuke this particle, let it respawn return CG_SetParticleActive(particle, ACT_NOT); } //checkvisibletime += trap_Milliseconds() - msec; return(qtrue); }
/** * @brief Generate rain particle * @details Attempt to 'spot' a raindrop somewhere below a sky texture. */ static qboolean CG_RainParticleGenerate(cg_atmosphericParticle_t *particle, vec3_t currvec, float currweight) { float angle = random() * 2 * M_PI, distance = 20 + MAX_ATMOSPHERIC_DISTANCE * random(); float groundHeight, skyHeight; particle->pos[0] = cg.refdef_current->vieworg[0] + sin(angle) * distance; particle->pos[1] = cg.refdef_current->vieworg[1] + cos(angle) * distance; // choose a spawn point randomly between sky and ground skyHeight = BG_GetSkyHeightAtPoint(particle->pos); if (skyHeight >= MAX_ATMOSPHERIC_HEIGHT) { return qfalse; } groundHeight = BG_GetSkyGroundHeightAtPoint(particle->pos); if (groundHeight + particle->height + ATMOSPHERIC_PARTICLE_OFFSET >= skyHeight) { return qfalse; } particle->pos[2] = groundHeight + random() * (skyHeight - groundHeight); // make sure it doesn't fall from too far cause it then will go over our heads ('lower the ceiling') if (cg_atmFx.baseHeightOffset > 0) { if (particle->pos[2] - cg.refdef_current->vieworg[2] > cg_atmFx.baseHeightOffset) { particle->pos[2] = cg.refdef_current->vieworg[2] + cg_atmFx.baseHeightOffset; if (particle->pos[2] < groundHeight) { return qfalse; } } } // rain goes in bursts - allow max raindrops every 10 seconds if (cg_atmFx.oldDropsActive > (0.50 * cg_atmFx.numDrops + 0.001 * cg_atmFx.numDrops * (10000 - (cg.time % 10000)))) { return qfalse; } CG_SetParticleActive(particle, ACT_FALLING); particle->colour[0] = 0.6 + 0.2 * random() * 0xFF; particle->colour[1] = 0.6 + 0.2 * random() * 0xFF; particle->colour[2] = 0.6 + 0.2 * random() * 0xFF; VectorCopy(currvec, particle->delta); particle->delta[2] += crandom() * 100; VectorCopy(particle->delta, particle->deltaNormalized); VectorNormalizeFast(particle->deltaNormalized); particle->height = ATMOSPHERIC_RAIN_HEIGHT + crandom() * 100; particle->weight = currweight; particle->effectshader = &cg_atmFx.effectshaders[0]; //particle->effectshader = &cg_atmFx.effectshaders[ (int) (random() * ( cg_atmFx.numEffectShaders - 1 )) ]; return qtrue; }
static qboolean CG_SnowParticleGenerate( cg_atmosphericParticle_t *particle, vec3_t currvec, float currweight ) { // Attempt to 'spot' a snowflake somewhere below a sky texture. float angle, distance; float groundHeight, skyHeight; // int msec = trap_Milliseconds(); // n_generatetime++; angle = random() * 2 * M_PI; distance = 20 + MAX_ATMOSPHERIC_DISTANCE * random(); particle->pos[0] = cg.refdef.vieworg[0] + sin( angle ) * distance; particle->pos[1] = cg.refdef.vieworg[1] + cos( angle ) * distance; // ydnar: choose a spawn point randomly between sky and ground skyHeight = BG_GetSkyHeightAtPoint( particle->pos ); if ( skyHeight == MAX_ATMOSPHERIC_HEIGHT ) { return qfalse; } groundHeight = BG_GetSkyGroundHeightAtPoint( particle->pos ); if ( groundHeight >= skyHeight ) { return qfalse; } particle->pos[2] = groundHeight + random() * ( skyHeight - groundHeight ); // make sure it doesn't fall from too far cause it then will go over our heads ('lower the ceiling') if ( cg_atmFx.baseHeightOffset > 0 ) { if ( particle->pos[2] - cg.refdef.vieworg[2] > cg_atmFx.baseHeightOffset ) { particle->pos[2] = cg.refdef.vieworg[2] + cg_atmFx.baseHeightOffset; if ( particle->pos[2] < groundHeight ) { return qfalse; } } } CG_SetParticleActive( particle, ACT_FALLING ); VectorCopy( currvec, particle->delta ); particle->delta[2] += crandom() * 25; VectorCopy( particle->delta, particle->deltaNormalized ); VectorNormalizeFast( particle->deltaNormalized ); particle->height = ATMOSPHERIC_SNOW_HEIGHT + random() * 2; particle->weight = particle->height * 0.5f; if (cg_atmFx.numEffectShaders > 1) { particle->effectshader = &cg_atmFx.effectshaders[ rand()%cg_atmFx.numEffectShaders ]; } else { particle->effectshader = &cg_atmFx.effectshaders[0]; } // generatetime += trap_Milliseconds() - msec; return( qtrue ); }
/** * @brief Generate a snowflake * @details Attempt to 'spot' a snowflake somewhere below a sky texture. */ static qboolean CG_SnowParticleGenerate(cg_atmosphericParticle_t *particle, vec3_t currvec, float currweight) { float angle = random() * 2 * M_PI, distance = 20 + MAX_ATMOSPHERIC_DISTANCE * random(); float groundHeight, skyHeight; particle->pos[0] = cg.refdef_current->vieworg[0] + sin(angle) * distance; particle->pos[1] = cg.refdef_current->vieworg[1] + cos(angle) * distance; // choose a spawn point randomly between sky and ground skyHeight = BG_GetSkyHeightAtPoint(particle->pos); if (skyHeight >= MAX_ATMOSPHERIC_HEIGHT) { return qfalse; } groundHeight = BG_GetSkyGroundHeightAtPoint(particle->pos); if (groundHeight + particle->height + ATMOSPHERIC_PARTICLE_OFFSET >= skyHeight) { return qfalse; } particle->pos[2] = groundHeight + random() * (skyHeight - groundHeight); // make sure it doesn't fall from too far cause it then will go over our heads ('lower the ceiling') if (cg_atmFx.baseHeightOffset > 0) { if (particle->pos[2] - cg.refdef_current->vieworg[2] > cg_atmFx.baseHeightOffset) { particle->pos[2] = cg.refdef_current->vieworg[2] + cg_atmFx.baseHeightOffset; if (particle->pos[2] < groundHeight) { return qfalse; } } } CG_SetParticleActive(particle, ACT_FALLING); VectorCopy(currvec, particle->delta); particle->delta[2] += crandom() * 25; VectorCopy(particle->delta, particle->deltaNormalized); VectorNormalizeFast(particle->deltaNormalized); particle->height = ATMOSPHERIC_SNOW_HEIGHT + random() * 2; particle->weight = particle->height * 0.5f; particle->effectshader = &cg_atmFx.effectshaders[0]; //particle->effectshader = &cg_atmFx.effectshaders[ (int) (random() * ( cg_atmFx.numEffectShaders - 1 )) ]; return qtrue; }
static qboolean CG_SnowParticleCheckVisible( cg_atmosphericParticle_t *particle ) { // Check the snowflake is visible and still going, wrapping if necessary. float moved; vec2_t distance; // int msec = trap_Milliseconds(); // n_checkvisibletime++; if( !particle || particle->active == ACT_NOT ) { // checkvisibletime += trap_Milliseconds() - msec; return( qfalse ); } moved = (cg.time - cg_atmFx.lastRainTime) * 0.001; // Units moved since last frame VectorMA( particle->pos, moved, particle->delta, particle->pos ); if( particle->pos[2] < BG_GetSkyGroundHeightAtPoint( particle->pos ) ) { // checkvisibletime += trap_Milliseconds() - msec; return CG_SetParticleActive( particle, ACT_NOT ); } distance[0] = particle->pos[0] - cg.refdef_current->vieworg[0]; distance[1] = particle->pos[1] - cg.refdef_current->vieworg[1]; if( (distance[0] * distance[0] + distance[1] * distance[1]) > Square( MAX_ATMOSPHERIC_DISTANCE ) ) { // ydnar: just nuke this particle, let it respawn return CG_SetParticleActive( particle, ACT_NOT ); /* // Attempt to respot the particle at our other side particle->pos[0] -= 1.85f * distance[0]; particle->pos[1] -= 1.85f * distance[1]; // ydnar: place particle in random position between ground and sky groundHeight = BG_GetSkyGroundHeightAtPoint( particle->pos ); skyHeight = BG_GetSkyHeightAtPoint( particle->pos ); if( skyHeight == MAX_ATMOSPHERIC_HEIGHT ) return CG_SetParticleActive( particle, ACT_NOT ); particle->pos[ 2 ] = groundHeight + random() * (skyHeight - groundHeight); // ydnar: valid spot? if( particle->pos[ 2 ] <= groundHeight || particle->pos[ 2 ] >= skyHeight ) return CG_SetParticleActive( particle, ACT_NOT ); */ } // checkvisibletime += trap_Milliseconds() - msec; return( qtrue ); }
static qboolean CG_RainParticleCheckVisible( cg_atmosphericParticle_t *particle ) { // Check the raindrop is visible and still going, wrapping if necessary. float moved; vec2_t distance; // int msec = trap_Milliseconds(); if( !particle || particle->active == ACT_NOT ) { // checkvisibletime += trap_Milliseconds() - msec; return( qfalse ); } moved = (cg.time - cg_atmFx.lastRainTime) * 0.001; // Units moved since last frame VectorMA( particle->pos, moved, particle->delta, particle->pos ); if( particle->pos[2] + particle->height < BG_GetSkyGroundHeightAtPoint( particle->pos ) ) { // checkvisibletime += trap_Milliseconds() - msec; return CG_SetParticleActive( particle, ACT_NOT ); } distance[0] = particle->pos[0] - cg.refdef_current->vieworg[0]; distance[1] = particle->pos[1] - cg.refdef_current->vieworg[1]; if( (distance[0] * distance[0] + distance[1] * distance[1]) > Square( MAX_ATMOSPHERIC_DISTANCE ) ) { // ydnar: just nuke this particle, let it respawn return CG_SetParticleActive( particle, ACT_NOT ); /* // Attempt to respot the particle at our other side particle->pos[0] -= 1.85f * distance[0]; particle->pos[1] -= 1.85f * distance[1]; // Valid spot? pointHeight = BG_GetSkyHeightAtPoint( particle->pos ); if( pointHeight == MAX_ATMOSPHERIC_HEIGHT ) { // checkvisibletime += trap_Milliseconds() - msec; return CG_SetParticleActive( particle, ACT_NOT ); } pointHeight = BG_GetSkyGroundHeightAtPoint( particle->pos ); if( pointHeight == MAX_ATMOSPHERIC_HEIGHT || pointHeight >= particle->pos[2] ) { // checkvisibletime += trap_Milliseconds() - msec; return CG_SetParticleActive( particle, ACT_NOT ); } */ } // checkvisibletime += trap_Milliseconds() - msec; return( qtrue ); }
/** * @brief Draw a snowflake * @details Render a snow particle. */ static void CG_SnowParticleRender(cg_atmosphericParticle_t *particle) { vec3_t forward, right; polyVert_t verts[3]; vec2_t line; float len, sinTumbling, cosTumbling, particleWidth, dist; vec3_t start, finish; float groundHeight; if (particle->active == ACT_NOT) { return; } if (CG_CullPoint(particle->pos)) { return; } VectorCopy(particle->pos, start); sinTumbling = sin(particle->pos[2] * 0.03125f * (0.5f * particle->weight)); cosTumbling = cos((particle->pos[2] + particle->pos[1]) * 0.03125f * (0.5f * particle->weight)); start[0] += 24 * (1 - particle->deltaNormalized[2]) * sinTumbling; start[1] += 24 * (1 - particle->deltaNormalized[2]) * cosTumbling; // make sure it doesn't clip through surfaces groundHeight = BG_GetSkyGroundHeightAtPoint(start); len = particle->height; if (start[2] - len - ATMOSPHERIC_PARTICLE_OFFSET <= groundHeight) { return; // stop snow going through surfaces //len = particle->height - groundHeight + start[2]; //VectorMA(start, len - particle->height, particle->deltaNormalized, start); } if (len <= 0) { return; } line[0] = particle->pos[0] - cg.refdef_current->vieworg[0]; line[1] = particle->pos[1] - cg.refdef_current->vieworg[1]; dist = DistanceSquared(particle->pos, cg.refdef_current->vieworg); // dist becomes scale if (dist > Square(500.f)) { dist = 1.f + ((dist - Square(500.f)) * (10.f / Square(2000.f))); } else { dist = 1.f; } len *= dist; VectorCopy(particle->deltaNormalized, forward); VectorMA(start, -(len /* sinTumbling */), forward, finish); line[0] = DotProduct(forward, cg.refdef_current->viewaxis[1]); line[1] = DotProduct(forward, cg.refdef_current->viewaxis[2]); VectorScale(cg.refdef_current->viewaxis[1], line[1], right); VectorMA(right, -line[0], cg.refdef_current->viewaxis[2], right); VectorNormalize(right); particleWidth = dist * (/* cosTumbling */ particle->weight); VectorMA(finish, -particleWidth, right, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorMA(start, -particleWidth, right, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorMA(start, particleWidth, right, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; CG_AddPolyToPool(*particle->effectshader, verts); }
/** * @brief Draw a raindrop * @details Render a rain particle. */ static void CG_RainParticleRender(cg_atmosphericParticle_t *particle) { vec3_t forward, right; polyVert_t verts[3]; vec2_t line; float len, dist; vec3_t start, finish; float groundHeight; if (particle->active == ACT_NOT) { return; } if (CG_CullPoint(particle->pos)) { return; } VectorCopy(particle->pos, start); dist = DistanceSquared(particle->pos, cg.refdef_current->vieworg); // make sure it doesn't clip through surfaces groundHeight = BG_GetSkyGroundHeightAtPoint(start); len = particle->height; if (start[2] - ATMOSPHERIC_PARTICLE_OFFSET <= groundHeight) { // stop rain going through surfaces len = particle->height - groundHeight + start[2]; VectorMA(start, len - particle->height, particle->deltaNormalized, start); } if (len <= 0) { return; } // fade nearby rain particles if (dist < Square(128.f)) { dist = .25f + .75f * (dist / Square(128.f)); } else { dist = 1.0f; } VectorCopy(particle->deltaNormalized, forward); VectorMA(start, -len, forward, finish); line[0] = DotProduct(forward, cg.refdef_current->viewaxis[1]); line[1] = DotProduct(forward, cg.refdef_current->viewaxis[2]); VectorScale(cg.refdef_current->viewaxis[1], line[1], right); VectorMA(right, -line[0], cg.refdef_current->viewaxis[2], right); VectorNormalize(right); VectorCopy(finish, verts[0].xyz); verts[0].st[0] = 0.5f; verts[0].st[1] = 0; verts[0].modulate[0] = particle->colour[0]; verts[0].modulate[1] = particle->colour[1]; verts[0].modulate[2] = particle->colour[2]; verts[0].modulate[3] = 100 * dist; VectorMA(start, -particle->weight, right, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = particle->colour[0]; verts[1].modulate[1] = particle->colour[1]; verts[2].modulate[2] = particle->colour[2]; verts[1].modulate[3] = 200 * dist; VectorMA(start, particle->weight, right, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = particle->colour[0]; verts[2].modulate[1] = particle->colour[1]; verts[2].modulate[2] = particle->colour[2]; verts[2].modulate[3] = 200 * dist; CG_AddPolyToPool(*particle->effectshader, verts); }
static void CG_RainParticleRender( cg_atmosphericParticle_t *particle ) { // Draw a raindrop vec3_t forward, right; polyVert_t verts[3]; vec2_t line; float len, frac, dist; vec3_t start, finish; float groundHeight; // int msec = trap_Milliseconds(); // n_rendertime++; if( particle->active == ACT_NOT ) { // rendertime += trap_Milliseconds() - msec; return; } if( CG_CullPoint( particle->pos ) ) { return; } VectorCopy( particle->pos, start ); dist = DistanceSquared( particle->pos, cg.refdef_current->vieworg ); // Make sure it doesn't clip through surfaces groundHeight = BG_GetSkyGroundHeightAtPoint( start ); len = particle->height; if( start[2] <= groundHeight ) { // Stop snow going through surfaces. len = particle->height - groundHeight + start[2]; frac = start[2]; VectorMA( start, len - particle->height, particle->deltaNormalized, start ); } if( len <= 0 ) { // rendertime += trap_Milliseconds() - msec; return; } // fade nearby rain particles if( dist < Square( 128.f ) ) dist = .25f + .75f * ( dist / Square( 128.f ) ); else dist = 1.0f; VectorCopy( particle->deltaNormalized, forward ); VectorMA( start, -len, forward, finish ); line[0] = DotProduct( forward, cg.refdef_current->viewaxis[1] ); line[1] = DotProduct( forward, cg.refdef_current->viewaxis[2] ); VectorScale( cg.refdef_current->viewaxis[1], line[1], right ); VectorMA( right, -line[0], cg.refdef_current->viewaxis[2], right ); VectorNormalize( right ); // dist = 1.0; VectorCopy( finish, verts[0].xyz ); verts[0].st[0] = 0.5f; verts[0].st[1] = 0; verts[0].modulate[0] = particle->colour[0]; verts[0].modulate[1] = particle->colour[1]; verts[0].modulate[2] = particle->colour[2]; verts[0].modulate[3] = 100 * dist; VectorMA( start, -particle->weight, right, verts[1].xyz ); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = particle->colour[0]; verts[1].modulate[1] = particle->colour[1]; verts[2].modulate[2] = particle->colour[2]; verts[1].modulate[3] = 200 * dist; VectorMA( start, particle->weight, right, verts[2].xyz ); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = particle->colour[0]; verts[2].modulate[1] = particle->colour[1]; verts[2].modulate[2] = particle->colour[2]; verts[2].modulate[3] = 200 * dist; CG_AddPolyToPool( *particle->effectshader, verts ); // rendertime += trap_Milliseconds() - msec; }
static qboolean CG_RainParticleGenerate( cg_atmosphericParticle_t *particle, vec3_t currvec, float currweight ) { // Attempt to 'spot' a raindrop somewhere below a sky texture. float angle, distance; float groundHeight, skyHeight; // int msec = trap_Milliseconds(); // n_generatetime++; angle = random() * 2*M_PI; distance = 20 + MAX_ATMOSPHERIC_DISTANCE * random(); particle->pos[0] = cg.refdef_current->vieworg[0] + sin(angle) * distance; particle->pos[1] = cg.refdef_current->vieworg[1] + cos(angle) * distance; // ydnar: choose a spawn point randomly between sky and ground skyHeight = BG_GetSkyHeightAtPoint( particle->pos ); if( skyHeight == MAX_ATMOSPHERIC_HEIGHT ) return qfalse; groundHeight = BG_GetSkyGroundHeightAtPoint( particle->pos ); if( groundHeight >= skyHeight ) return qfalse; particle->pos[2] = groundHeight + random() * (skyHeight - groundHeight); // make sure it doesn't fall from too far cause it then will go over our heads ('lower the ceiling') if( cg_atmFx.baseHeightOffset > 0 ) { if( particle->pos[2] - cg.refdef_current->vieworg[2] > cg_atmFx.baseHeightOffset ) { particle->pos[2] = cg.refdef_current->vieworg[2] + cg_atmFx.baseHeightOffset; if( particle->pos[2] < groundHeight ) { return qfalse; } } } // ydnar: rain goes in bursts { float maxActiveDrops; // every 10 seconds allow max raindrops maxActiveDrops = 0.50 * cg_atmFx.numDrops + 0.001 * cg_atmFx.numDrops * (10000 - (cg.time % 10000)); if( cg_atmFx.oldDropsActive > maxActiveDrops ) return qfalse; } CG_SetParticleActive( particle, ACT_FALLING ); particle->colour[0] = 0.6 + 0.2 * random() * 0xFF; particle->colour[1] = 0.6 + 0.2 * random() * 0xFF; particle->colour[2] = 0.6 + 0.2 * random() * 0xFF; VectorCopy( currvec, particle->delta ); particle->delta[2] += crandom() * 100; VectorCopy( particle->delta, particle->deltaNormalized ); VectorNormalizeFast( particle->deltaNormalized ); particle->height = ATMOSPHERIC_RAIN_HEIGHT + crandom() * 100; particle->weight = currweight; particle->effectshader = &cg_atmFx.effectshaders[0]; // particle->effectshader = &cg_atmFx.effectshaders[ (int) (random() * ( cg_atmFx.numEffectShaders - 1 )) ]; // generatetime += trap_Milliseconds() - msec; return( qtrue ); }