/** * @brief Add atmospheric effects * @details Add atmospheric effects (e.g. rain, snow etc.) to view] */ void CG_AddAtmosphericEffects() { int curr, max, currnum; cg_atmosphericParticle_t *particle; vec3_t currvec; float currweight; if (cg_atmFx.numDrops <= 0 || cg_atmFx.numEffectShaders == 0 || cg_atmosphericEffects.value <= 0) { return; } max = cg_atmosphericEffects.value < 1 ? cg_atmosphericEffects.value * cg_atmFx.numDrops : cg_atmFx.numDrops; if (CG_EffectGustCurrent(currvec, &currweight, &currnum)) { // recalculate gust parameters CG_EffectGust(); } // allow parametric management of drop count for swelling/waning precip cg_atmFx.oldDropsActive = cg_atmFx.dropsActive; cg_atmFx.dropsActive = 0; cg_atmFx.dropsCreated = 0; VectorSet(cg_atmFx.viewDir, cg.refdef_current->viewaxis[0][0], cg.refdef_current->viewaxis[0][1], 0.f); for (curr = 0; curr < max; curr++) { particle = &cg_atmFx.particles[curr]; if (!cg_atmFx.ParticleCheckVisible(particle)) { // effect has terminated or fallen from screen view if (!cg_atmFx.ParticleGenerate(particle, currvec, currweight)) { continue; } else { cg_atmFx.dropsCreated++; } } cg_atmFx.ParticleRender(particle); cg_atmFx.dropsActive++; } cg_atmFx.lastRainTime = cg.time; }
void CG_AddAtmosphericEffects() { // Add atmospheric effects (e.g. rain, snow etc.) to view int curr, max, currnum; cg_atmosphericParticle_t *particle; vec3_t currvec; float currweight; if (cg_atmFx.numDrops <= 0 || cg_atmFx.numEffectShaders == 0) return; max = cg_lowEffects.integer ? (cg_atmFx.numDrops >> 1) : cg_atmFx.numDrops; if (CG_EffectGustCurrent(currvec, &currweight, &currnum)) CG_EffectGust(); // Recalculate gust parameters for (curr = 0; curr < max; curr++) { particle = &cg_atmFx.particles[curr]; if (!cg_atmFx.ParticleCheckVisible(particle)) { // Effect has terminated / fallen from screen view if (!particle->nextDropTime) { // Stop rain being synchronized particle->nextDropTime = rand() % ATMOSPHERIC_DROPDELAY; } else if (currnum < curr || particle->nextDropTime > cg.time) continue; if (!cg_atmFx.ParticleGenerate(particle, currvec, currweight)) { // Ensure it doesn't attempt to generate every frame, to prevent // 'clumping' when there's only a small sky area available. particle->nextDropTime = cg.time + ATMOSPHERIC_DROPDELAY; continue; } } cg_atmFx.ParticleRender(particle); } cg_atmFx.lastRainTime = cg.time; }
void CG_EffectParse(const char *effectstr) { // Split the string into it's component parts. float bmin, bmax, cmin, cmax, gmin, gmax, bdrop, gdrop, wsplash, lsplash; int count; char *startptr, *eqptr, *endptr, *type; char workbuff[128]; if (CG_AtmosphericKludge()) return; // Set up some default values cg_atmFx.baseVec[0] = cg_atmFx.baseVec[1] = 0; cg_atmFx.gustVec[0] = cg_atmFx.gustVec[1] = 100; bmin = 5; bmax = 10; cmin = 1; cmax = 1; gmin = 0; gmax = 2; bdrop = gdrop = 300; cg_atmFx.baseWeight = 0.7f; cg_atmFx.gustWeight = 1.5f; wsplash = 1; lsplash = 1; type = NULL; // Parse the parameter string Q_strncpyz(workbuff, effectstr, sizeof(workbuff)); for (startptr = workbuff; *startptr;) { for (eqptr = startptr; *eqptr && *eqptr != '=' && *eqptr != ','; eqptr++); if (!*eqptr) break; // No more string if (*eqptr == ',') { startptr = eqptr + 1; // Bad argument, continue continue; } *eqptr++ = 0; for (endptr = eqptr; *endptr && *endptr != ','; endptr++); if (*endptr) *endptr++ = 0; if (!type) { if (Q_stricmp(startptr, "T")) { cg_atmFx.numDrops = 0; CG_Printf("Atmospheric effect must start with a type.\n"); return; } if (!Q_stricmp(eqptr, "RAIN")) { type = "rain"; cg_atmFx.ParticleCheckVisible = &CG_RainParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_RainParticleGenerate; cg_atmFx.ParticleRender = &CG_RainParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_RAIN_SPEED; } else if (!Q_stricmp(eqptr, "SNOW")) { type = "snow"; cg_atmFx.ParticleCheckVisible = &CG_RainParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_SnowParticleGenerate; cg_atmFx.ParticleRender = &CG_SnowParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_SNOW_SPEED; } else { cg_atmFx.numDrops = 0; CG_Printf("Only effect type 'rain' and 'snow' are supported.\n"); return; } } else { if (!Q_stricmp(startptr, "B")) CG_EP_ParseFloats(eqptr, &bmin, &bmax); else if (!Q_stricmp(startptr, "C")) CG_EP_ParseFloats(eqptr, &cmin, &cmax); else if (!Q_stricmp(startptr, "G")) CG_EP_ParseFloats(eqptr, &gmin, &gmax); else if (!Q_stricmp(startptr, "BV")) CG_EP_ParseFloats(eqptr, &cg_atmFx.baseVec[0], &cg_atmFx.baseVec[1]); else if (!Q_stricmp(startptr, "GV")) CG_EP_ParseFloats(eqptr, &cg_atmFx.gustVec[0], &cg_atmFx.gustVec[1]); else if (!Q_stricmp(startptr, "W")) CG_EP_ParseFloats(eqptr, &cg_atmFx.baseWeight, &cg_atmFx.gustWeight); else if (!Q_stricmp(startptr, "S")) CG_EP_ParseFloats(eqptr, &wsplash, &lsplash); else if (!Q_stricmp(startptr, "D")) CG_EP_ParseFloats(eqptr, &bdrop, &gdrop); else CG_Printf("Unknown effect key '%s'.\n", startptr); } startptr = endptr; } if (!type) { // No effects cg_atmFx.numDrops = -1; return; } cg_atmFx.baseMinTime = 1000 * bmin; cg_atmFx.baseMaxTime = 1000 * bmax; cg_atmFx.changeMinTime = 1000 * cmin; cg_atmFx.changeMaxTime = 1000 * cmax; cg_atmFx.gustMinTime = 1000 * gmin; cg_atmFx.gustMaxTime = 1000 * gmax; cg_atmFx.baseDrops = bdrop; cg_atmFx.gustDrops = gdrop; cg_atmFx.waterSplash = wsplash; cg_atmFx.landSplash = lsplash; cg_atmFx.numDrops = (cg_atmFx.baseDrops > cg_atmFx.gustDrops) ? cg_atmFx.baseDrops : cg_atmFx.gustDrops; if (cg_atmFx.numDrops > MAX_ATMOSPHERIC_PARTICLES) cg_atmFx.numDrops = MAX_ATMOSPHERIC_PARTICLES; // Load graphics // Rain if (!Q_stricmp(type, "rain")) { cg_atmFx.numEffectShaders = 1; if (!(cg_atmFx.effectshaders[0] = trap_R_RegisterShader("gfx/atmosphere/raindrop"))) cg_atmFx.effectshaders[0] = -1; if (cg_atmFx.waterSplash) cg_atmFx.effectwatershader = trap_R_RegisterShader("gfx/atmosphere/raindropwater"); if (cg_atmFx.landSplash) cg_atmFx.effectlandshader = trap_R_RegisterShader("gfx/atmosphere/raindropsolid"); // Snow } else if (!Q_stricmp(type, "snow")) { for (cg_atmFx.numEffectShaders = 0; cg_atmFx.numEffectShaders < 6; cg_atmFx.numEffectShaders++) { if (! (cg_atmFx.effectshaders[cg_atmFx.numEffectShaders] = trap_R_RegisterShader(va("gfx/atmosphere/snowflake0%i", cg_atmFx.numEffectShaders)))) cg_atmFx.effectshaders[cg_atmFx.numEffectShaders] = -1; // we had some kind of a problem } cg_atmFx.waterSplash = 0; cg_atmFx.landSplash = 0; // This really should never happen } else cg_atmFx.numEffectShaders = 0; // Initialise atmospheric effect to prevent all particles falling at the start for (count = 0; count < cg_atmFx.numDrops; count++) cg_atmFx.particles[count].nextDropTime = ATMOSPHERIC_DROPDELAY + (rand() % ATMOSPHERIC_DROPDELAY); CG_EffectGust(); }
/** * @brief Parse effect * @details Split the string into it's component parts. */ void CG_EffectParse(const char *effectstr) { float bmin, bmax, cmin, cmax, gmin, gmax, bdrop, gdrop /*, wsplash, lsplash*/; int bheight; char *startptr, *eqptr, *endptr; char workbuff[128]; atmFXType_t atmFXType = ATM_NONE; if (CG_AtmosphericKludge()) { return; } // set up some default values cg_atmFx.baseVec[0] = cg_atmFx.baseVec[1] = 0; cg_atmFx.gustVec[0] = cg_atmFx.gustVec[1] = 100; bmin = 5; bmax = 10; cmin = 1; cmax = 1; gmin = 0; gmax = 2; bdrop = gdrop = 300; cg_atmFx.baseWeight = 0.7f; cg_atmFx.gustWeight = 1.5f; bheight = 0; // parse the parameter string Q_strncpyz(workbuff, effectstr, sizeof(workbuff)); for (startptr = workbuff; *startptr; ) { for (eqptr = startptr; *eqptr && *eqptr != '=' && *eqptr != ','; eqptr++) ; if (!*eqptr) { break; // No more string } if (*eqptr == ',') { startptr = eqptr + 1; // Bad argument, continue continue; } *eqptr++ = 0; for (endptr = eqptr; *endptr && *endptr != ','; endptr++) ; if (*endptr) { *endptr++ = 0; } if (atmFXType == ATM_NONE) { if (Q_stricmp(startptr, "T")) { cg_atmFx.numDrops = 0; CG_Printf("Atmospheric effect must start with a type.\n"); return; } if (!Q_stricmp(eqptr, "RAIN")) { atmFXType = ATM_RAIN; cg_atmFx.ParticleCheckVisible = &CG_RainParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_RainParticleGenerate; cg_atmFx.ParticleRender = &CG_RainParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_RAIN_SPEED; } else if (!Q_stricmp(eqptr, "SNOW")) { atmFXType = ATM_SNOW; cg_atmFx.ParticleCheckVisible = &CG_SnowParticleCheckVisible; cg_atmFx.ParticleGenerate = &CG_SnowParticleGenerate; cg_atmFx.ParticleRender = &CG_SnowParticleRender; cg_atmFx.baseVec[2] = cg_atmFx.gustVec[2] = -ATMOSPHERIC_SNOW_SPEED; } else { cg_atmFx.numDrops = 0; CG_Printf("Only effect type 'rain' and 'snow' are supported.\n"); return; } } else { if (!Q_stricmp(startptr, "B")) { CG_EP_ParseFloats(eqptr, &bmin, &bmax); } else if (!Q_stricmp(startptr, "C")) { CG_EP_ParseFloats(eqptr, &cmin, &cmax); } else if (!Q_stricmp(startptr, "G")) { CG_EP_ParseFloats(eqptr, &gmin, &gmax); } else if (!Q_stricmp(startptr, "BV")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.baseVec[0], &cg_atmFx.baseVec[1]); } else if (!Q_stricmp(startptr, "GV")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.gustVec[0], &cg_atmFx.gustVec[1]); } else if (!Q_stricmp(startptr, "W")) { CG_EP_ParseFloats(eqptr, &cg_atmFx.baseWeight, &cg_atmFx.gustWeight); } else if (!Q_stricmp(startptr, "D")) { CG_EP_ParseFloats(eqptr, &bdrop, &gdrop); } else if (!Q_stricmp(startptr, "H")) { CG_EP_ParseInts(eqptr, &bheight, &bheight); } else { CG_Printf("Unknown effect key '%s'.\n", startptr); } } startptr = endptr; } if (atmFXType == ATM_NONE || !BG_LoadTraceMap(cgs.rawmapname, cg.mapcoordsMins, cg.mapcoordsMaxs)) { // no effects cg_atmFx.numDrops = -1; return; } cg_atmFx.baseHeightOffset = bheight; if (cg_atmFx.baseHeightOffset < 0) { cg_atmFx.baseHeightOffset = 0; } cg_atmFx.baseMinTime = 1000 * bmin; cg_atmFx.baseMaxTime = 1000 * bmax; cg_atmFx.changeMinTime = 1000 * cmin; cg_atmFx.changeMaxTime = 1000 * cmax; cg_atmFx.gustMinTime = 1000 * gmin; cg_atmFx.gustMaxTime = 1000 * gmax; cg_atmFx.baseDrops = bdrop; cg_atmFx.gustDrops = gdrop; cg_atmFx.numDrops = (cg_atmFx.baseDrops > cg_atmFx.gustDrops) ? cg_atmFx.baseDrops : cg_atmFx.gustDrops; if (cg_atmFx.numDrops > MAX_ATMOSPHERIC_PARTICLES) { cg_atmFx.numDrops = MAX_ATMOSPHERIC_PARTICLES; } // load graphics if (atmFXType == ATM_RAIN) // rain { cg_atmFx.numEffectShaders = 1; cg_atmFx.effectshaders[0] = trap_R_RegisterShader("gfx/misc/raindrop"); if (!(cg_atmFx.effectshaders[0])) { cg_atmFx.effectshaders[0] = -1; cg_atmFx.numEffectShaders = 0; } } else if (atmFXType == ATM_SNOW) // snow { cg_atmFx.numEffectShaders = 1; cg_atmFx.effectshaders[0] = trap_R_RegisterShader("gfx/misc/snow"); } else { // this really should never happen cg_atmFx.numEffectShaders = 0; } CG_EffectGust(); }
void CG_AddAtmosphericEffects() { // Add atmospheric effects (e.g. rain, snow etc.) to view int curr, max, currnum; cg_atmosphericParticle_t *particle; vec3_t currvec; float currweight; if( cg_atmFx.numDrops <= 0 || cg_atmFx.numEffectShaders == 0 || cg_atmosphericEffects.value <= 0 ) return; #ifndef ATM_NEW CG_ClearPolyPool(); #endif // ATM_NEW max = cg_atmosphericEffects.value < 1 ? cg_atmosphericEffects.value * cg_atmFx.numDrops : cg_atmFx.numDrops; if( CG_EffectGustCurrent( currvec, &currweight, &currnum ) ) CG_EffectGust(); // Recalculate gust parameters // ydnar: allow parametric management of drop count for swelling/waning precip cg_atmFx.oldDropsActive = cg_atmFx.dropsActive; cg_atmFx.dropsActive = 0; cg_atmFx.dropsRendered = cg_atmFx.dropsCreated = cg_atmFx.dropsSkipped = 0; // getgroundtime = getskytime = rendertime = checkvisibletime = generatetime = 0; // n_getgroundtime = n_getskytime = n_rendertime = n_checkvisibletime = n_generatetime = 0; VectorSet( cg_atmFx.viewDir, cg.refdef_current->viewaxis[0][0], cg.refdef_current->viewaxis[0][1], 0.f ); for( curr = 0; curr < max; curr++ ) { particle = &cg_atmFx.particles[curr]; //% if( !CG_SnowParticleCheckVisible( particle ) ) if( !cg_atmFx.ParticleCheckVisible( particle ) ) { // Effect has terminated / fallen from screen view /* if( !particle->nextDropTime ) { // Stop rain being synchronized particle->nextDropTime = cg.time + rand() % ATMOSPHERIC_DROPDELAY; } if( currnum < curr || particle->nextDropTime > cg.time ) { cg_atmFx.dropsRendered++; continue; } */ //% if( !CG_SnowParticleGenerate( particle, currvec, currweight ) ) if( !cg_atmFx.ParticleGenerate( particle, currvec, currweight ) ) { // Ensure it doesn't attempt to generate every frame, to prevent // 'clumping' when there's only a small sky area available. particle->nextDropTime = cg.time + ATMOSPHERIC_DROPDELAY; continue; } else { cg_atmFx.dropsCreated++; } } //% CG_RainParticleRender( particle ); cg_atmFx.ParticleRender( particle ); cg_atmFx.dropsActive++; } // CG_RenderPolyPool(); cg_atmFx.lastRainTime = cg.time; // CG_Printf( "Active: %d Generated: %d Rendered: %d Skipped: %d\n", cg_atmFx.dropsActive, cg_atmFx.dropsCreated, cg_atmFx.dropsRendered, cg_atmFx.dropsSkipped ); // CG_Printf( "gg: %i gs: %i rt: %i cv: %i ge: %i\n", getgroundtime, getskytime, rendertime, checkvisibletime, generatetime ); // CG_Printf( "\\-> %i \\-> %i \\-> %i \\-> %i \\-> %i\n", n_getgroundtime, n_getskytime, n_rendertime, n_checkvisibletime, n_generatetime ); }