Esempio n. 1
0
/**
 * @brief Particle tracing with caching
 */
static trace_t PTL_Trace (ptl_t* ptl, const AABB& aabb)
{
	static ptlTraceCache_t ptlCache;
	const float epsilonPos = 3.0f;
	const float epsilonBBox = 1.0f;

	if (VectorCompareEps(ptlCache.start, ptl->origin, epsilonPos) && VectorCompareEps(ptlCache.end, ptl->s, epsilonPos)
			&& VectorCompareEps(ptlCache.pBox.mins, aabb.mins, epsilonBBox) && VectorCompareEps(ptlCache.pBox.maxs, aabb.maxs, epsilonBBox)) {
		ptlCache.count++;
		return ptlCache.trace;
	}

	VectorCopy(ptl->origin, ptlCache.start);
	VectorCopy(ptl->s, ptlCache.end);
	ptlCache.pBox.set(aabb);

	ptlCache.trace = CL_Trace(Line(ptl->origin, ptl->s), aabb, nullptr, nullptr, MASK_SOLID, cl.mapMaxLevel - 1);
	return ptlCache.trace;
}
Esempio n. 2
0
/**
 * @brief Particle tracing with caching
 */
static inline trace_t PTL_Trace (ptl_t *ptl, const vec3_t mins, const vec3_t maxs)
{
	static ptlTraceCache_t ptlCache;
	const float epsilonPos = 3.0f;
	const float epsilonBBox = 1.0f;

	if (VectorCompareEps(ptlCache.start, ptl->origin, epsilonPos) && VectorCompareEps(ptlCache.end, ptl->s, epsilonPos)
			&& VectorCompareEps(ptlCache.mins, mins, epsilonBBox) && VectorCompareEps(ptlCache.maxs, maxs, epsilonBBox)) {
		ptlCache.count++;
		return ptlCache.trace;
	}

	VectorCopy(ptl->origin, ptlCache.start);
	VectorCopy(ptl->s, ptlCache.end);
	VectorCopy(mins, ptlCache.mins);
	VectorCopy(maxs, ptlCache.maxs);

	ptlCache.trace = CL_Trace(ptl->origin, ptl->s, AABB(mins, maxs), nullptr, nullptr, MASK_SOLID, cl.mapMaxLevel - 1);
	return ptlCache.trace;
}
Esempio n. 3
0
static void LE_PlayFootStepSound (le_t* le)
{
	if (Q_strvalid(le->teamDef->footstepSound)) {
		S_LoadAndPlaySample(le->teamDef->footstepSound, le->origin, SOUND_ATTN_NORM, SND_VOLUME_FOOTSTEPS);
		return;
	}
	/* walking in water will not play the normal footstep sounds */
	if (!le->pathContents[le->pathPos]) {
		vec3_t from, to;

		/* prepare trace vectors */
		PosToVec(le->pos, from);
		VectorCopy(from, to);
		/* we should really hit the ground with this */
		to[2] -= UNIT_HEIGHT;

		const trace_t trace = CL_Trace(Line(from, to), AABB::EMPTY, nullptr, nullptr, MASK_SOLID, cl_worldlevel->integer);
		if (trace.surface)
			LE_PlaySoundFileAndParticleForSurface(le, trace.surface->name);
	} else
		LE_PlaySoundFileForContents(le, le->pathContents[le->pathPos]);
}
Esempio n. 4
0
/*
===============
CL_AddParticles
===============
*/
void CL_AddParticles (void)
{
	cparticle_t		*p, *next;
	float			alpha;
	float			time, time2;
	vec3_t			org;
	int				color;
	cparticle_t		*active, *tail;
	int             contents;
	float			grav;

	active = NULL;
	tail = NULL;

	if (!cl_drawParticles->integer)
		return;

	// allow gravity tweaks by the server
	grav = Cvar_VariableValue("sv_gravity");
	if (!grav)
		grav = 1;
	else
		grav /= 800;

	for (p = active_particles; p; p = next)
	{
		next = p->next;

		// set alpha
		// PMM - added INSTANT_PARTICLE handling
		if (p->alphavel != INSTANT_PARTICLE)
		{
			time = (cl.time - p->time) * 0.001;
			alpha = p->alpha + time * p->alphavel;

			if (alpha <= 0)
			{
				// faded out
				CL_FreeParticle (p);
				continue;
			}
			else if (alpha <= 0.3f && p->color == 240) // this is HACK central...
			{
				// do blood decals
				if (rand() & 4)
				{
					trace_t tr;

					time2 = time * time;
					org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2;
					org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2;
					org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2;

					tr = CL_Trace(p->org, org, 0, MASK_SOLID);
					if (tr.fraction != 1.0f)
					{
						if (!VectorCompare(tr.plane.normal, vec3_origin) && !(CM_PointContents(p->org, 0) & MASK_WATER)) // no blood splatters underwater...
						{
							vec4_t color;
							Vector4Set(color, 1.0, 0.0, 0.0, 1.0f);
							RE_AddDecal(tr.endpos, tr.plane.normal, color, 16 + ((rand() % 21 * 0.05f) - 0.5f), DECAL_BLOOD + (rand() & 4), 0, frand() * 360);
						}
					}
				}
			}
		}
		else
		{
			alpha = p->alpha;
		}

		if (alpha > 1.0)
			alpha = 1;

		// set color
		color = p->color;

		// backup old position
		VectorCopy (p->org, p->oldOrg);

		// calculate new position
		time2 = time * time;

		org[0] = p->org[0] + p->vel[0] * time + p->accel[0] * time2;
		org[1] = p->org[1] + p->vel[1] * time + p->accel[1] * time2;
		org[2] = p->org[2] + p->vel[2] * time + p->accel[2] * time2;

		// gravity modulation
		//if (!p->ignoreGrav)
		//	org[2] += time2 * -PARTICLE_GRAVITY;

		// collision test
		if (cl_particleCollision->integer)
		{
			if (p->bounceFactor)
			{
				trace_t trace;
				vec3_t vel;
				int hitTime;
				float time;

				trace = CL_Trace(p->oldOrg, org, 0, CONTENTS_SOLID);
				if (trace.fraction > 0 && trace.fraction < 1)
				{
					// reflect the velocity on the trace plane
					hitTime = cl.time - cls.rframetime + cls.rframetime * trace.fraction;

					time = ((float)hitTime - p->time) * 0.001;

					Vector3Set (vel, p->vel[0], p->vel[1], p->vel[2] + p->accel[2] * time * grav);
					VectorReflect (vel, trace.plane.normal, p->vel);
					VectorScale (p->vel, p->bounceFactor, p->vel);

					// check for stop, making sure that even on low FPS systems it doesn't bobble
					if (trace.allsolid || (trace.plane.normal[2] > 0 && (p->vel[2] < 40 || p->vel[2] < -cls.rframetime * p->vel[2])))
					{
						VectorClear(p->vel);
						VectorClear(p->accel);

						p->bounceFactor = 0.0f;
					}

					VectorCopy (trace.endpos, org);

					// reset particle
					p->time = cl.time;

					VectorCopy (org, p->org);
				}
			}
		}

		// kill all particles in solid
		contents = CM_PointContents (org, 0);
		if (contents & MASK_SOLID)
		{
			CL_FreeParticle (p);
			continue;
		}

		// have this always below CL_FreeParticle(p); !
		p->next = NULL;
		if (!tail)
		{
			active = tail = p;
		}
		else
		{
			tail->next = p;
			tail = p;
		}

		// add to scene
		V_AddParticle (org, color, alpha);

		// PMM
		if (p->alphavel == INSTANT_PARTICLE)
		{
			p->alphavel = 0.0;
			p->alpha = 0.0;
		}
	}

	active_particles = active;
}
Esempio n. 5
0
/*
=================
RE_AddDecal

Adds a single decal to the decal list
=================
*/
void RE_GL_AddDecal (vec3_t origin, vec3_t dir, vec4_t color, float size, int type, int flags, float angle)
{
	int			i, j, numfragments;
	vec3_t		verts[MAX_DECAL_VERTS], shade, temp;
	markFragment_t *fr, fragments[MAX_FRAGMENTS_PER_DECAL];
	vec3_t		axis[3];
	cdecal_t	*d;
	float		lightspot[3];

	if (!gl_decals->value)
		return;

	// invalid decal size
	if (size <= 0)
		return;

	// a hack to produce decals from explosions etc
	if (VectorCompare(dir, vec3_origin))
	{
		float	scale = 1.5 * size;
		trace_t	trace;
		vec3_t	end, dirs[6] = {
				{ 1.0, 0.0, 0.0 },
				{ -1.0, 0.0, 0.0 },
				{ 0.0, 1.0, 0.0 },
				{ 0.0, -1.0, 0.0 },
				{ 0.0, 0.0, 1.0 },
				{ 0.0, 0.0, -1.0 }
		};

		for (i = 0; i < 6; i++)
		{
			VectorMA(origin, scale, dirs[i], end);
			trace = CL_Trace(origin, end, 0, MASK_SOLID);
			if (trace.fraction != 1.0)
				RE_GL_AddDecal(origin, trace.plane.normal, color, size, type, flags, angle);
		}
		return;
	}

	// calculate orientation matrix
	VectorNormalize2(dir, axis[0]);
	PerpendicularVector(axis[1], axis[0]);
	RotatePointAroundVector(axis[2], axis[0], axis[1], angle);
	CrossProduct(axis[0], axis[2], axis[1]);

	// clip it against the world
	numfragments = R_GetClippedFragments(origin, axis, size, MAX_DECAL_VERTS, verts, MAX_FRAGMENTS_PER_DECAL, fragments);
	if (!numfragments)
		return; // no valid fragments

	// store out vertex data
	size = 0.5f / size;
	VectorScale(axis[1], size, axis[1]);
	VectorScale(axis[2], size, axis[2]);

	for (i = 0, fr = fragments; i < numfragments; i++, fr++)
	{
		// check if we have hit the max
		if (fr->numPoints > MAX_DECAL_VERTS)
			fr->numPoints = MAX_DECAL_VERTS;
		else if (fr->numPoints <= 0)
			continue;

		d = R_AllocDecal();

		d->time = r_newrefdef.time;

		d->node = fr->node;

		VectorCopy(fr->surf->plane->normal, d->direction);
		if (!(fr->surf->flags & SURF_PLANEBACK))
			VectorNegate(d->direction, d->direction); // reverse direction

		Vector4Set(d->color, color[0], color[1], color[2], color[3]);
		VectorCopy(origin, d->org);

		//if (flags & DF_SHADE)
		{
			R_LightPoint(origin, shade, lightspot);
			for (j = 0; j < 3; j++)
				d->color[j] = (d->color[j] * shade[j] * 0.6) + (d->color[j] * 0.4);
		}
		d->type = type;
		d->flags = flags;

		// make the decal vert
		d->numverts = fr->numPoints;
		for (j = 0; j < fr->numPoints && j < MAX_VERTS_PER_FRAGMENT; j++)
		{
			// xyz
			VectorCopy(verts[fr->firstPoint + j], d->verts[j]);

			// st
			VectorSubtract(d->verts[j], origin, temp);
			d->stcoords[j][0] = DotProduct(temp, axis[1]) + 0.5f;
			d->stcoords[j][1] = DotProduct(temp, axis[2]) + 0.5f;
		}
	}
}
Esempio n. 6
0
/**
 * @brief Updates weather for the time passed; handles particle creation/removal automatically
 */
void Weather::update (int milliseconds)
{
	/* Don't play the weather particles if the user doesn't want them */
	if (!Cvar_GetInteger("cl_particleweather")) {
		/* This makes weather look very weird if it is enabled mid-battle */
		/* clearParticles(); */
		return;
	}

	size_t dead = 0;
	/* physics: check for ttl and move live particles */
	for (size_t i = 0; i < Weather::MAX_PARTICLES; i++) {
		Weather::particle &prt = particles[i];
		if (prt.ttl < 0) {
			dead++;
			continue;
		} else { /** @todo creates vanishing-before-impact particles at low framerates -- should improve that somehow */
			int restOfLife = prt.ttl -= milliseconds;
			if (restOfLife < 0) {
				if (fabs(prt.vz) < 0.001f || splashTime < 1) {
					/* either no splash or is a splash particle dying */
					dead++;
					continue;
				}
				/* convert it into splash particle */
				/* technically, we should complete the last frame of movement, but with current particle types it looks good even without it */
				prt.vz = 0; prt.vx = 0; prt.vy = 0;
				prt.ttl += splashTime;
			}
		}
		/* if we got so far, particle is alive and probably needs a physics update */
		const int timeAfterUpdate = prt.timeout -= milliseconds;
		const float moveDuration = milliseconds * 0.001f;

		prt.x += prt.vx * moveDuration; prt.y += prt.vy * moveDuration; prt.z += prt.vz * moveDuration;

		if (timeAfterUpdate > 0) {
			/* just move linearly */
			continue;
		}
		/* alter motion vector */
		/** @todo */
	}
	/* create new ones in place of dead */
	if (dead) {
		const float windX = cos(windDirection) * (windStrength + crand() * windTurbulence);
		const float windY = sin(windDirection) * (windStrength + crand() * windTurbulence);

		AABB weatherZone; /** < extents of zone in which weather particles will be rendered */
		weatherZone = cl.mapData->mapBox;
		weatherZone.expandXY(256);
		weatherZone.maxs[2] += 512;

		Line prtPath;

		if (dead > 200) dead = 200; /* avoid creating too much particles in the single frame, it could kill the low-end hardware */

		int debugCreated = 0;
		for (size_t i = 0; dead &&  i < Weather::MAX_PARTICLES && i < weatherStrength * Weather::MAX_PARTICLES; i++) {
			Weather::particle &prt = particles[i];
			if (prt.ttl >= 0)
				continue;
			prt.x = (frand() * (weatherZone.getMaxX() - weatherZone.getMinX())) + weatherZone.getMinX();
			prt.y = (frand() * (weatherZone.getMaxY() - weatherZone.getMinY())) + weatherZone.getMinY();
			prt.z = weatherZone.getMaxZ();

			prt.vx = windX;
			prt.vy = windY;
			prt.vz = -fallingSpeed * (frand() * 0.2f + 0.9f);

			float lifeTime = (weatherZone.getMaxZ() - weatherZone.getMinZ()) / -prt.vz; /* default */

			VectorSet(prtPath.start, prt.x, prt.y, prt.z);
			VectorSet(prtPath.stop, prt.x + prt.vx * lifeTime, prt.y + prt.vy * lifeTime, prt.z + prt.vz * lifeTime);

			trace_t trace = CL_Trace(prtPath, AABB::EMPTY, nullptr, nullptr, MASK_SOLID, cl.mapMaxLevel - 1); /* find the collision point */
			lifeTime *= trace.fraction;

			prt.ttl = 1000 * lifeTime; /* convert to milliseconds */

			prt.timeout = prt.ttl + 1000000; /** @todo proper code for physics */
			debugCreated++;
			dead--;
		}
	}
#if 0
	if (debugCreated) Com_Printf("created %i weather particles\n", debugCreated);
#endif
}