Exemple #1
0
TEST_F(ParticleTest, FloodParticles)
{
	for (int i = 0; i < MAX_PTLS; i++) {
		ASSERT_TRUE(nullptr != CL_ParticleSpawn("fire", 0xFF, vec3_origin));
	}
	CL_ParticleRun();
	ASSERT_TRUE(nullptr == CL_ParticleSpawn("fire", 0xFF, vec3_origin));
}
Exemple #2
0
/**
 * @brief Called every frame and checks whether a timed particle should be spawned
 */
static void CL_ParticleRunTimed (void)
{
	int i;
	const size_t length = lengthof(timedParticles);

	for (i = 0; i < length; i++) {
		timedParticle_t *tp = &timedParticles[i];
		if (!tp->parent || !tp->parent->inuse)
			continue;
		if (tp->n >= tp->max)
			continue;
		if (CL_Milliseconds() - tp->lastTime < tp->dt)
			continue;
		{
			ptl_t *p;
			if (!tp->n) {
				/* first spawn? - then copy the parent values. We have to
				 * do this here and now earlier because projectile particles
				 * get these values set after spawn. */
				VectorCopy(tp->parent->s, tp->s);
				VectorCopy(tp->parent->v, tp->v);
				VectorCopy(tp->parent->a, tp->a);
			}
			tp->n++;
			tp->lastTime = CL_Milliseconds();
			p = CL_ParticleSpawn(tp->ptl, tp->levelFlags, tp->s, tp->v, tp->a);
			if (p && tp->children) {
				p->next = tp->parent->children;
				p->parent = tp->parent;
				tp->parent->children = p;
			}
		}
	}
}
Exemple #3
0
static void CL_RunMapParticles (void)
{
	mapParticle_t *mp;
	ptl_t *ptl;
	int i;

	for (i = 0, mp = mapParticles; i < cl.numMapParticles; i++, mp++)
		if (mp->nextTime && cl.time >= mp->nextTime) {
			/* spawn a new particle */
			ptl = CL_ParticleSpawn(mp->ptl, mp->levelflags, mp->origin);
			if (!ptl) {
				Com_Printf(S_COLOR_YELLOW "Could not spawn particle '%s'\n", mp->ptl);
				mp->nextTime = 0;
				continue;
			}

			/* init the particle */
			CL_ParseMapParticle(ptl, mp->info, false);
			CL_ParticleFunction(ptl, ptl->ctrl->init);
			CL_ParseMapParticle(ptl, mp->info, true);

			/* prepare next spawning */
			if (Vector2NotEmpty(mp->wait))
				mp->nextTime += mp->wait[0] + mp->wait[1] * frand();
			else
				mp->nextTime = 0;
		}
}
Exemple #4
0
/**
 * @note Think function
 */
static void LET_Projectile (le_t* le)
{
	if (cl.time >= le->endTime) {
		vec3_t impact;
		VectorCopy(le->origin, impact);
		CL_ParticleFree(le->ptl);
		/* don't run the think function again */
		le->inuse = false;
		if (Q_strvalid(le->ref1)) {
			VectorCopy(le->ptl->s, impact);
			le->ptl = CL_ParticleSpawn(le->ref1, 0, impact, bytedirs[le->angle]);
			VecToAngles(bytedirs[le->state], le->ptl->angles);
		}
		if (Q_strvalid(le->ref2)) {
			S_LoadAndPlaySample(le->ref2, impact, le->fd->impactAttenuation, SND_VOLUME_WEAPONS);
		}
		if (le->ref3) {
			/* Spawn blood particles (if defined) if actor(-body) was hit. Even if actor is dead. */
			/** @todo Special particles for stun attack (mind you that there is
			 * electrical and gas/chemical stunning)? */
			if (le->fd->obj->dmgtype != csi.damStunGas)
				LE_ActorBodyHit(le->ref3, impact, le->angle);
			CL_ActorPlaySound(le->ref3, SND_HURT);
		}
	} else if (CL_OutsideMap(le->ptl->s, UNIT_SIZE * 10)) {
		le->endTime = cl.time;
		CL_ParticleFree(le->ptl);
		/* don't run the think function again */
		le->inuse = false;
	}
}
Exemple #5
0
/**
 * @brief Spawns particle effects for a hit actor.
 * @param[in] le The actor to spawn the particles for.
 * @param[in] impact The impact location (where the particles are spawned).
 * @param[in] normal The index of the normal vector of the particles (think: impact angle).
 */
static void LE_ActorBodyHit (const le_t* le, const vec3_t impact, int normal)
{
	if (le->teamDef) {
		/* Spawn "hit_particle" if defined in teamDef. */
		if (le->teamDef->hitParticle[0] != '\0')
			CL_ParticleSpawn(le->teamDef->hitParticle, 0, impact, bytedirs[normal]);
	}
}
/**
 * @brief Let a particle spawn for the client
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg holds the network data
 * @sa CL_ParticleSpawn
 * @sa EV_PARTICLE_SPAWN
 */
void CL_ParticleSpawnEvent (const eventRegister_t* self, dbuffer* msg)
{
	char particle[MAX_VAR];
	int levelflags;
	vec3_t s, v, a;

	/* read data */
	NET_ReadFormat(msg, self->formatString, &levelflags, &s, &v, &a, particle, sizeof(particle));

	CL_ParticleSpawn(particle, levelflags, s, v, a);
}
Exemple #7
0
/**
 * @brief Spawns a debug marker particle in the world
 */
static void PTL_DebugSpawnMarker_f (void)
{
	vec3_t worldOrigin;

	if (Cmd_Argc() < 4) {
		Com_Printf("Usage: %s <x> <y> <z>\n", Cmd_Argv(0));
		return;
	}

	worldOrigin[0] = atof(Cmd_Argv(1));
	worldOrigin[1] = atof(Cmd_Argv(2));
	worldOrigin[2] = atof(Cmd_Argv(3));

	CL_ParticleSpawn("debug_marker", 0, worldOrigin);
}
/**
 * @brief draw a simple 'spotted' line from a spotter to the spotted
 */
static void CL_DrawLineOfSight (const le_t *watcher, const le_t *target)
{
	ptl_t *ptl;
	vec3_t eyes;

	if (!watcher || !target)
		return;

	/* start is the watchers origin */
	VectorCopy(watcher->origin, eyes);
	if (LE_IsCrouched(watcher))
		eyes[2] += EYE_HT_CROUCH;
	else
		eyes[2] += EYE_HT_STAND;

	ptl = CL_ParticleSpawn("fadeTracer", 0, eyes, target->origin);

	if (LE_IsCivilian(target))
		VectorSet(ptl->color, 0.2, 0.2, 1);
}
Exemple #9
0
/**
 * @param[in] fd The grenade fire definition
 * @param[in] flags bitmask: SF_BODY, SF_IMPACT, SF_BOUNCING, SF_BOUNCED
 * @param[in] muzzle starting/location vector
 * @param[in] v0 velocity vector
 * @param[in] dt delta seconds
 * @param[in] leVictim The actor the grenade is thrown at (not yet supported)
 */
void LE_AddGrenade (const fireDef_t* fd, int flags, const vec3_t muzzle, const vec3_t v0, int dt, le_t* leVictim)
{
	/* add le */
	le_t* le = LE_Add(0);
	if (!le)
		return;
	LE_SetInvisible(le);

	/* bind particle */
	vec3_t accel;
	VectorSet(accel, 0, 0, -GRAVITY);
	le->ptl = CL_ParticleSpawn(fd->projectile, 0, muzzle, v0, accel);
	if (!le->ptl) {
		le->inuse = false;
		return;
	}
	/* particle properties */
	VectorSet(le->ptl->angles, 360 * crand(), 360 * crand(), 360 * crand());
	VectorSet(le->ptl->omega, 500 * crand(), 500 * crand(), 500 * crand());

	/* think function */
	if (flags & SF_BODY) {
		le->ref1 = fd->hitBody;
		le->ref2 = fd->hitBodySound;
		le->ref3 = leVictim;
	} else if ((flags & SF_IMPACT) || (fd->splrad && !fd->bounce)) {
		le->ref1 = fd->impact;
		le->ref2 = fd->impactSound;
	} else {
		le->ref1 = nullptr;
		if (flags & SF_BOUNCING)
			le->ref2 = fd->bounceSound;
	}

	le->endTime = cl.time + dt;
	/* direction - bytedirs index (0,0,1) */
	le->angle = 5;
	le->fd = fd;
	LE_SetThink(le, LET_Projectile);
	LE_ExecuteThink(le);
}
/**
 * @brief Let a particle appear for the client
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg holds the network data
 * @sa CL_ParticleSpawn
 * @sa EV_PARTICLE_APPEAR
 */
void CL_ParticleAppear (const eventRegister_t* self, dbuffer* msg)
{
	char particle[MAX_VAR];
	int entnum, levelflags;
	vec3_t origin;

	/* read data */
	NET_ReadFormat(msg, self->formatString, &entnum, &levelflags, origin, particle, sizeof(particle));

	le_t* le = LE_Get(entnum);
	if (!le)
		LE_NotFoundError(entnum);

	/* particles don't have a model to add to the scene - we mark them as invisible and
	 * only render the particle */
	LE_SetInvisible(le);
	le->levelflags = levelflags;
	le->particleID = Mem_PoolStrDup(particle, cl_genericPool, 0);
	le->ptl = CL_ParticleSpawn(le->particleID, le->levelflags, origin);
	if (!le->ptl)
		Com_Printf("Could not spawn particle: '%s'\n", le->particleID);
}
Exemple #11
0
/**
 * @brief Plays step sounds and draw particles for different terrain types
 * @param[in] le The local entity to play the sound and draw the particle for
 * @param[in] textureName The name of the texture the actor is standing on
 * @sa LET_PathMove
 */
static void LE_PlaySoundFileAndParticleForSurface (le_t* le, const char* textureName)
{
	const terrainType_t* t = Com_GetTerrainType(textureName);
	if (!t)
		return;

	/* origin might not be up-to-date here - but pos should be */
	vec3_t origin;
	PosToVec(le->pos, origin);

	/** @todo use the Grid_Fall method (ACTOR_SIZE_NORMAL) to ensure, that the particle is
	 * drawn at the ground (if needed - maybe the origin is already ground aligned)*/
	if (t->particle) {
		/* check whether actor is visible */
		if (!LE_IsStunned(le) && LE_IsLivingAndVisibleActor(le))
			CL_ParticleSpawn(t->particle, 0, origin);
	}
	if (t->footstepSound) {
		Com_DPrintf(DEBUG_SOUND, "LE_PlaySoundFileAndParticleForSurface: volume %.2f\n", t->footstepVolume);
		S_LoadAndPlaySample(t->footstepSound, origin, SOUND_ATTN_STATIC, t->footstepVolume);
	}
}
Exemple #12
0
static void CL_ParticleFunction (ptl_t *p, ptlCmd_t *cmd)
{
	int stackIdx;
	ptrdiff_t e;
	int type;
	int i, j, n;
	void *cmdData;
	float arg;
	ptl_t *pnew;

	/* test for null cmd */
	if (!cmd)
		return;

	/* run until finding PC_END */
	for (stackIdx = 0, e = 0; cmd->cmd != PC_END; cmd++) {
		if (cmd->ref > RSTACK)
			cmdData = CL_ParticleCommandGetDataLocation(p, cmd);
		else {
			if (!stackIdx)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			/* pop an element off the stack */
			e = (byte *) stackPtr[--stackIdx] - cmdStack;

			i = RSTACK - cmd->ref;
			if (!i) {
				/* normal stack reference */
				cmdData = stackPtr[stackIdx];
				cmd->type = stackType[stackIdx];
			} else {
				/* stack reference to element of vector */
				if ((1 << stackType[stackIdx]) & V_VECS) {
					cmd->type = V_FLOAT;
					cmdData = (float *) stackPtr[stackIdx] + (i - 1);
				} else {
					Com_Error(ERR_DROP, "CL_ParticleFunction: can't get components of a non-vector type (particle %s)", p->ctrl->name);
				}
			}
		}

		switch (cmd->cmd) {
		case PC_PUSH:
			/* check for stack overflow */
			if (stackIdx >= MAX_STACK_DEPTH)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack overflow");

			/* store the value in the stack */
			stackPtr[stackIdx] = &cmdStack[e];
			stackType[stackIdx] = cmd->type;
			e += Com_SetValue(stackPtr[stackIdx++], cmdData, (valueTypes_t)cmd->type, 0, 0);
			break;

		case PC_POP:
		case PC_KPOP:
			/* check for stack underflow */
			if (stackIdx == 0)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			/* get pics and models */
			if (offsetof(ptl_t, pic) == -cmd->ref) {
				if (stackType[--stackIdx] != V_STRING)
					Com_Error(ERR_DROP, "Bad type '%s' for pic (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
				p->pic = CL_ParticleGetArt((char *) stackPtr[stackIdx], p->frame, ART_PIC);
				e = (byte *) stackPtr[stackIdx] - cmdStack;
				break;
			}
			if (offsetof(ptl_t, model) == -cmd->ref) {
				if (stackType[--stackIdx] != V_STRING)
					Com_Error(ERR_DROP, "Bad type '%s' for model (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
				p->model = CL_ParticleGetArt((char *) stackPtr[stackIdx], p->frame, ART_MODEL);
				e = (byte *) stackPtr[stackIdx] - cmdStack;
				break;
			}
			if (offsetof(ptl_t, program) == -cmd->ref) {
				if (stackType[--stackIdx] != V_STRING)
					Com_Error(ERR_DROP, "Bad type '%s' for program (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
				p->program = R_LoadProgram((char *) stackPtr[stackIdx], R_InitParticleProgram, R_UseParticleProgram);
				if (p->program)
					p->program->userdata = p;
				e = (byte *) stackPtr[stackIdx] - cmdStack;
				break;
			}

			/* get different data */
			if (cmd->cmd == PC_POP)
				e -= Com_SetValue(cmdData, stackPtr[--stackIdx], (valueTypes_t)cmd->type, 0, 0);
			else
				Com_SetValue(cmdData, stackPtr[stackIdx - 1], (valueTypes_t)cmd->type, 0, 0);
			break;

		case PC_ADD:
		case PC_SUB:
			/* check for stack underflow */
			if (stackIdx == 0)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			type = stackType[stackIdx - 1];
			if (!((1 << type) & V_VECS))
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for add (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);

			/* float based vector addition */
			if (type != cmd->type)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for add/sub (particle %s)", p->ctrl->name);

			n = type - V_FLOAT + 1;

			for (i = 0; i < n; i++) {
				if (cmd->cmd == PC_SUB)
					arg = -(*((float *) cmdData + i));
				else
					arg = *((float *) cmdData + i);
				*((float *) stackPtr[stackIdx - 1] + i) += arg;
			}
			break;

		case PC_MUL:
		case PC_DIV:
			/* check for stack underflow */
			if (stackIdx == 0)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			type = stackType[stackIdx - 1];
			if (!((1 << type) & V_VECS))
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for add (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);

			n = type - V_FLOAT + 1;

			if (type > V_FLOAT && cmd->type > V_FLOAT) {
				/* component wise multiplication */
				if (type != cmd->type)
					Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for mul/div (particle %s)", p->ctrl->name);

				for (i = 0; i < n; i++) {
					if (cmd->cmd == PC_DIV)
						arg = 1.0 / (*((float *) cmdData + i));
					else
						arg = *((float *) cmdData + i);
					*((float *) stackPtr[stackIdx - 1] + i) *= arg;
				}
				break;
			}

			if (cmd->type > V_FLOAT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad vector dimensions for mul/div (particle %s)", p->ctrl->name);

			/* scalar multiplication with scalar in second argument */
			if (cmd->cmd == PC_DIV)
				arg = 1.0 / (*(float *) cmdData);
			else
				arg = *(float *) cmdData;
			for (i = 0; i < n; i++)
				*((float *) stackPtr[stackIdx - 1] + i) *= arg;

			break;

		case PC_SIN:
			if (cmd->type != V_FLOAT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for sin (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
			stackPtr[stackIdx] = &cmdStack[e];
			stackType[stackIdx] = cmd->type;
			*(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI));
			e += sizeof(float);
			break;

		case PC_COS:
			if (cmd->type != V_FLOAT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for cos (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
			stackPtr[stackIdx] = &cmdStack[e];
			stackType[stackIdx] = cmd->type;
			*(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI));
			e += sizeof(float);
			break;

		case PC_TAN:
			if (cmd->type != V_FLOAT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for tan (particle %s)", vt_names[stackType[stackIdx - 1]], p->ctrl->name);
			stackPtr[stackIdx] = &cmdStack[e];
			stackType[stackIdx] = cmd->type;
			*(float *) stackPtr[stackIdx++] = sin(*(float *) cmdData * (2 * M_PI));
			e += sizeof(float);
			break;

		case PC_RAND:
		case PC_CRAND:
			stackPtr[stackIdx] = &cmdStack[e];
			stackType[stackIdx] = cmd->type;

			n = cmd->type - V_FLOAT + 1;

			if (cmd->cmd == PC_RAND)
				for (i = 0; i < n; i++)
					*((float *) stackPtr[stackIdx] + i) = *((float *) cmdData + i) * frand();
			else
				for (i = 0; i < n; i++)
					*((float *) stackPtr[stackIdx] + i) = *((float *) cmdData + i) * crand();

			e += n * sizeof(float);
			stackIdx++;
			break;

		case PC_V2:
		case PC_V3:
		case PC_V4:
			n = cmd->cmd - PC_V2 + 2;
			j = 0;

			if (stackIdx < n)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			for (i = 0; i < n; i++) {
				if (!((1 << stackType[--stackIdx]) & V_VECS))
					Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' for vector creation (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name);
				j += stackType[stackIdx] - V_FLOAT + 1;
			}

			if (j > 4)
				Com_Error(ERR_DROP, "CL_ParticleFunction: created vector with dim > 4 (particle %s)", p->ctrl->name);

			stackType[stackIdx++] = V_FLOAT + j - 1;
			break;

		case PC_KILL:
			CL_ParticleFree(p);
			return;

		case PC_SPAWN:
			pnew = CL_ParticleSpawn((const char *) cmdData, p->levelFlags, p->s, p->v, p->a);
			if (!pnew)
				Com_Printf("PC_SPAWN: Could not spawn child particle for '%s' (%s)\n", p->ctrl->name, (const char *) cmdData);
			break;

		case PC_TNSPAWN:
			/* check for stack underflow */
			if (stackIdx < 2)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			/* pop elements off the stack */
			/* amount of timed particles */
			type = stackType[--stackIdx];
			if (type != V_INT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for tnspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name);
			n = *(int *) stackPtr[stackIdx];

			/* delta time */
			type = stackType[--stackIdx];
			if (type != V_INT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for tnspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name);
			i = *(int *) stackPtr[stackIdx];

			/** @todo make the children boolean configurable */
			CL_ParticleSpawnTimed((const char *) cmdData, p, true, i, n);

			e -= 2 * sizeof(int);

			break;

		case PC_NSPAWN:
			/* check for stack underflow */
			if (stackIdx == 0)
				Com_Error(ERR_DROP, "CL_ParticleFunction: stack underflow");

			type = stackType[--stackIdx];
			if (type != V_INT)
				Com_Error(ERR_DROP, "CL_ParticleFunction: bad type '%s' int required for nspawn (particle %s)", vt_names[stackType[stackIdx]], p->ctrl->name);

			n = *(int *) stackPtr[stackIdx];
			e -= sizeof(int);

			for (i = 0; i < n; i++) {
				pnew = CL_ParticleSpawn((const char *) cmdData, p->levelFlags, p->s, p->v, p->a);
				if (!pnew)
					Com_Printf("PC_NSPAWN: Could not spawn child particle for '%s'\n", p->ctrl->name);
			}
			break;

		case PC_CHILD:
			pnew = CL_ParticleSpawn((const char *)cmdData, p->levelFlags, p->s, p->v, p->a);
			if (pnew) {
				pnew->next = p->children;
				pnew->parent = p;
				p->children = pnew;
			} else {
				Com_Printf("PC_CHILD: Could not spawn child particle for '%s'\n", p->ctrl->name);
			}
			break;

		default:
			Com_Error(ERR_DROP, "CL_ParticleFunction: unknown cmd type %i", cmd->type);
			break;
		}
	}
}
Exemple #13
0
/**
 * @brief Draw a model from the battlescape entity list
 * @sa R_GetEntityLists
 */
void R_DrawAliasModel (entity_t *e)
{
	mAliasModel_t *mod = &e->model->alias;
	/* the values are sane here already - see R_GetEntityLists */
	const image_t *skin = mod->meshes[e->as.mesh].skins[e->skinnum].skin;
	int i;
	float g;
	vec4_t color = {0.8, 0.8, 0.8, 1.0};
	mAliasMesh_t *mesh;

	/* IR goggles override color for entities that are affected */
	if ((refdef.rendererFlags & RDF_IRGOGGLES) && (e->flags & RF_IRGOGGLES))
		Vector4Set(e->shell, 1.0, 0.3, 0.3, 1.0);

	if (e->flags & RF_PULSE) {  /* and then adding in a pulse */
		const float f = 1.0 + sin((refdef.time + (e->model->alias.meshes[0].num_tris)) * 6.0) * 0.33;
		VectorScale(color, 1.0 + f, color);
	}

	g = 0.0;
	/* find brightest component */
	for (i = 0; i < 3; i++) {
		if (color[i] > g)  /* keep it */
			g = color[i];
	}

	/* scale it back to 1.0 */
	if (g > 1.0)
		VectorScale(color, 1.0 / g, color);

	R_Color(color);

	assert(skin->texnum > 0);
	R_BindTexture(skin->texnum);

	R_EnableGlowMap(skin->glowmap);

	R_UpdateLightList(e);
	R_EnableModelLights(e->lights, e->numLights, e->inShadow, true);

	/** @todo this breaks the encapsulation - don't call CL_* functions from within the renderer code */
	if (r_debug_lights->integer) {
		for (i = 0; i < e->numLights && i < r_dynamic_lights->integer; i++)
			CL_ParticleSpawn("lightTracerDebug", 0, e->transform.matrix + 12, e->lights[i]->origin);
	}

	if (skin->normalmap)
		R_EnableBumpmap(skin->normalmap);

	if (skin->specularmap)
		R_EnableSpecularMap(skin->specularmap, true);

	if (skin->roughnessmap)
		R_EnableRoughnessMap(skin->roughnessmap, true);

	glPushMatrix();
	glMultMatrixf(e->transform.matrix);

	if (VectorNotEmpty(e->scale))
		glScalef(e->scale[0], e->scale[1], e->scale[2]);

	mesh = R_DrawAliasModelBuffer(e);

	if (r_state.specularmap_enabled)
		R_EnableSpecularMap(NULL, false);

	if (r_state.roughnessmap_enabled)
		R_EnableRoughnessMap(NULL, false);

	R_EnableModelLights(NULL, 0, false, false);

	R_EnableGlowMap(NULL);

	if (r_state.active_normalmap)
		R_EnableBumpmap(NULL);

	R_DrawMeshShadow(e, mesh);

	if (mod->num_frames == 1)
		R_ResetArraysAfterStaticMeshRender();

	glPopMatrix();

	/* show model bounding box */
	if (r_showbox->integer)
		R_DrawBoundingBox(mod->frames[e->as.frame].mins, mod->frames[e->as.frame].maxs);

	R_Color(NULL);
}
Exemple #14
0
void LE_AddProjectile (const fireDef_t* fd, int flags, const vec3_t muzzle, const vec3_t impact, int normal, le_t* leVictim)
{
	/* add le */
	le_t* le = LE_Add(0);
	if (!le)
		return;
	LE_SetInvisible(le);
	/* bind particle */
	le->ptl = CL_ParticleSpawn(fd->projectile, 0, muzzle);
	if (!le->ptl) {
		le->inuse = false;
		return;
	}

	/* calculate parameters */
	vec3_t delta;
	VectorSubtract(impact, muzzle, delta);
	const float dist = VectorLength(delta);

	VecToAngles(delta, le->ptl->angles);
	/* direction - bytedirs index */
	le->angle = normal;
	le->fd = fd;

	/* infinite speed projectile? */
	if (!fd->speed) {
		le->inuse = false;
		le->ptl->size[0] = dist;
		VectorMA(muzzle, 0.5, delta, le->ptl->s);
		if ((flags & (SF_IMPACT | SF_BODY)) || (fd->splrad && !fd->bounce)) {
			ptl_t* ptl = nullptr;
			const float* dir = bytedirs[le->angle];
			if (flags & SF_BODY) {
				if (fd->hitBodySound != nullptr) {
					S_LoadAndPlaySample(fd->hitBodySound, le->origin, le->fd->impactAttenuation, SND_VOLUME_WEAPONS);
				}
				if (fd->hitBody != nullptr)
					ptl = CL_ParticleSpawn(fd->hitBody, 0, impact, dir);

				/* Spawn blood particles (if defined) if actor(-body) was hit. Even if actor is dead. */
				/** @todo Special particles for stun attack (mind you that there is
				 * electrical and gas/chemical stunning)? */
				if (leVictim) {
					if (fd->obj->dmgtype != csi.damStunGas)
						LE_ActorBodyHit(leVictim, impact, le->angle);
					if (fd->damage[0] >= 0)
						CL_ActorPlaySound(leVictim, SND_HURT);
				}
			} else {
				if (fd->impactSound != nullptr) {
					S_LoadAndPlaySample(fd->impactSound, le->origin, le->fd->impactAttenuation, SND_VOLUME_WEAPONS);
				}
				if (fd->impact != nullptr)
					ptl = CL_ParticleSpawn(fd->impact, 0, impact, dir);
			}
			if (ptl)
				VecToAngles(dir, ptl->angles);
		}
		return;
	}
	/* particle properties */
	VectorScale(delta, fd->speed / dist, le->ptl->v);
	le->endTime = cl.time + 1000 * dist / fd->speed;

	/* think function */
	if (flags & SF_BODY) {
		le->ref1 = fd->hitBody;
		le->ref2 = fd->hitBodySound;
		le->ref3 = leVictim;
	} else if ((flags & SF_IMPACT) || (fd->splrad && !fd->bounce)) {
		le->ref1 = fd->impact;
		le->ref2 = fd->impactSound;
	} else {
		le->ref1 = nullptr;
		if (flags & SF_BOUNCING)
			le->ref2 = fd->bounceSound;
	}

	LE_SetThink(le, LET_Projectile);
	LE_ExecuteThink(le);
}
Exemple #15
0
/**
 * @sa CL_ViewRender
 * @sa CL_AddUGV
 * @sa CL_AddActor
 */
void LE_AddToScene (void)
{
	for (int i = 0; i < cl.numLEs; i++) {
		le_t& le = cl.LEs[i];
		if (le.flags & LE_REMOVE_NEXT_FRAME) {
			le.inuse = false;
			le.flags &= ~LE_REMOVE_NEXT_FRAME;
		}
		if (le.inuse && !LE_IsInvisible(&le)) {
			if (le.flags & LE_CHECK_LEVELFLAGS) {
				if (!((1 << cl_worldlevel->integer) & le.levelflags))
					continue;
			} else if (le.flags & LE_ALWAYS_VISIBLE) {
				/* show them always */
			} else if (le.pos[2] > cl_worldlevel->integer)
				continue;

			entity_t ent(RF_NONE);
			ent.alpha = le.alpha;

			VectorCopy(le.angles, ent.angles);
			ent.model = le.model1;
			ent.skinnum = le.bodySkin;
			ent.lighting = &le.lighting;

			switch (le.contents) {
			/* Only breakables do not use their origin; func_doors and func_rotating do!!!
			 * But none of them have animations. */
			case CONTENTS_SOLID:
			case CONTENTS_DETAIL: /* they use mins/maxs */
				break;
			default:
				/* set entity values */
				R_EntitySetOrigin(&ent, le.origin);
				VectorCopy(le.origin, ent.oldorigin);
				/* store animation values */
				ent.as = le.as;
				break;
			}

			if (LE_IsOriginBrush(&le)) {
				ent.isOriginBrushModel = true;
				R_EntitySetOrigin(&ent, le.origin);
				VectorCopy(le.origin, ent.oldorigin);
			}

			if (LE_IsSelected(&le) && le.clientAction != nullptr) {
				const le_t* action = le.clientAction;
				if (action->inuse && action->type > ET_NULL && action->type < ET_MAX)
					LE_AddEdictHighlight(action);
			}

			/* call add function */
			/* if it returns false, don't draw */
			if (le.addFunc)
				if (!le.addFunc(&le, &ent))
					continue;

			/* add it to the scene */
			R_AddEntity(&ent);

			if (cl_le_debug->integer)
				CL_ParticleSpawn("cross", 0, le.origin);
		}
	}
}