⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 particle.c

📁 著名物理引擎Hawk的源代码
💻 C
字号:
/* particle.c, HAWK game engine
 *
 * Copyright 1997-1998 by Phil Frisbie, Jr.
 * for Hawk Software
 *
 */

#include "hawk.h"
#include "internal.h"
#include "particle.h"

int			nparticles;
int			nfreeparticles;
PARTICLE	*firstparticle;
PARTICLE	*firstfreeparticle;
PARTICLE	*particles;
PARTICLE	*lastparticle;
static BOOL	needinit = TRUE;


void partInit(void)
{
	int	i;

	renTextPrint("Initializing particle system\n");

	particles = TagMalloc(MAX_PARTICLES * sizeof(particles[0]), TAG_GAME);
	memset(particles, 0, MAX_PARTICLES * sizeof(particles[0]));
	nparticles = 0;
	nfreeparticles = MAX_PARTICLES - 1;

	for(i=0;i<MAX_PARTICLES;i++)
	{
		if(i != (MAX_PARTICLES - 1))
			particles[i].next = &particles[i+1];
		else
			particles[i].next = NULL;
		if(i != 0)
			particles[i].prev = &particles[i-1];
		else
			particles[i].prev = NULL;
	}
	firstfreeparticle = &particles[0];
	firstparticle = NULL;
	lastparticle = NULL;
	needinit = FALSE;
}

PARTICLE *partAdd(void)
{
	PARTICLE *p;

	if(needinit)
		partInit();
	if(!nfreeparticles)
		return NULL;

	p = firstfreeparticle;
	/* unchain from free */
	firstfreeparticle = firstfreeparticle->next;
	firstfreeparticle->prev = NULL;
	/* chain into used */
	if(!nparticles)/* first particle */
	{
		p->next = NULL;
		p->prev = NULL;
		firstparticle = p;
	}
	else
	{
		lastparticle->next = p;
		p->next = NULL;
		p->prev = lastparticle;
	}

	lastparticle = p;
	nparticles++;
	nfreeparticles--;
	return p;
}

void partFree(PARTICLE *p)
{
	PARTICLE *prev = p->prev;
	PARTICLE *next = p->next;

	/* unchain from used */
	if(nparticles == 1)/*this is the only particle */
	{
		firstparticle = NULL;
	}
	else if(p == firstparticle)/* this is the first in the chain */
	{
		firstparticle = next;
		firstparticle->prev = NULL;
	}
	else if(p == lastparticle)/* this is the last in the chain */
	{
		lastparticle = prev;
		lastparticle->next = NULL;
	}
	else				/* somewhere in the middle of the chain */
	{
		prev->next = next;
		next->prev = prev;
	}
	/* clear out old info */
	memset(p, 0, sizeof(PARTICLE));

	/* chain into free */
	firstfreeparticle->prev = p;
	p->next = firstfreeparticle;
	p->prev = NULL;
	firstfreeparticle = p;
	nparticles--;
	nfreeparticles++;

}

PARTICLE *partAdd2(void)
{
	int i;

	if(nparticles == 0) /* cannot chain the first particle */
	{
		particles[0].next = NULL;
		particles[0].alive = TRUE;
		nparticles++;
		firstparticle = &particles[0];
		return &particles[0];
	}
	else /* find an unused particle */
	{
		for(i=0;i<MAX_PARTICLES;i++)
		{
			if(particles[i].alive == FALSE) /* found an unused particle */
			{
				int j;
				/* find the last object in the chain */
				for(j=0;j<MAX_OBJECTS;j++)
				{
					if((!particles[j].next)
							&& (particles[j].alive)) /* found the last used particle in the chain */
					{
						particles[j].next = &particles[i];
						particles[i].next = NULL;
						particles[i].alive = TRUE;
						nparticles++;
						return &particles[i];
					}
				}
			}
		}
	}
	/* we must be out of particles */
	return NULL;
}

/*
 * partClampMove
 *
 *  Takes two movement vectors, om (the original), and nm (the new vector)
 *  and clamps to zero if the movement crosses 0.
 */

void partClampMove(vec3_t om, vec3_t nm)
{
	if((om[X] > 0) && (nm[X] < 0))
		nm[X] = 0;
	if((om[X] < 0) && (nm[X] > 0))
		nm[X] = 0;

	if((om[Y] > 0) && (nm[Y] < 0))
		nm[Y] = 0;
	if((om[Y] < 0) && (nm[Y] > 0))
		nm[Y] = 0;

	if((om[Z] > 0) && (nm[Z] < 0))
		nm[Z] = 0;
	if((om[Z] < 0) && (nm[Z] > 0))
		nm[Z] = 0;
}

/*
 * partClampColor
 *
 *  Clamps the (float) RGB color to between 0.0 and 1.0
 */

void partClampColor(vec3_t c)
{
	if(c[R] < 0)
		c[R] = 0;
	if(c[R] > 1)
		c[R] = 1;

	if(c[G] < 0)
		c[G] = 0;
	if(c[G] > 1)
		c[G] = 1;

	if(c[B] < 0)
		c[B] = 0;
	if(c[B] > 1)
		c[B] = 1;
}

/*
 * partUpdate
 *
 *  Updates each particle in the chain, deleting those that have expired.
 */

void partUpdate(void)
{
	PARTICLE	*p, *lastp;
	int			f = Engine.curframes;
	int			t = Engine.gameframes;
	int			count = 0;

	if(!nparticles) /* if no particles, return */
		return;
	if(f < 1) /* skip update until next frame */
		return;
	lastp = NULL;
	p = firstparticle;

	do
	{
		int i;

		count++;
		if(count > nparticles)
			count--;
		if(t > p->death) /* time to delete */
		{
			PARTICLE *nextp = p->next;

			partFree(p);
			p = nextp;
			continue;
		}
		/* move the particle */
		i = f;
		do
		{
			vec3_t	m;

			VectorCopy(p->move, m);
			VectorSubtract(m, p->decay, m);
			if(p->gravity)
			{
				m[Z] -= 0.08;
			}
			VectorCopy(m, p->move);		/* update particle move vector */
			VectorAdd(p->center, m, p->center);
		}while(--i);

		/* update the color */
		i = f;
		do
		{
			VectorAdd(p->color, p->colorchange, p->color);
			partClampColor(p->color);
		}while(--i);

		lastp = p;
		p = p->next;
	}while(p);
}

/*
 * randomMove
 *
 *  Creates a random movement vector, scaled to maxspeed.
 */

void randomMove(vec3_t m, float maxspeed)
{
	float len;

	m[X] = (maxspeed * ((float)rand()) / ((float)RAND_MAX)) - (maxspeed / 2);
	m[Y] = (maxspeed * ((float)rand()) / ((float)RAND_MAX)) - (maxspeed / 2);
	m[Z] = (maxspeed * ((float)rand()) / ((float)RAND_MAX)) - (maxspeed / 2);

	len = VectorLength(m);
	VectorNormalize(m, m);
	VectorScale(m, maxspeed , m);

}

/*
 * randomTime
 *
 *  Returns a random time between 1/2 t and t.
 */

int randomTime(int	t)
{
	return(int)(t / 2 * ((float)rand()) / ((float)RAND_MAX)) + (t / 2);
}

/*
 * partExplosion
 *
 *  Creates a simple explosion.
 */

void partExplosion(vec3_t center, int number)
{
	int i;

	i = number;

	do
	{
		PARTICLE	*p;

		p = partAdd();
		if(!p)
			return;
		p->size = 32.0f;
		VectorCopy(center, p->center);
		randomMove(p->move, 1.0f);
		p->decay[X] = 0.0f;
		p->decay[Y] = 0.0f;
		p->decay[Z] = 0.0f;
		p->color[R] = 1.0f;
		p->color[G] = 1.0f;
		p->color[B] = 1.0f;
		p->colorchange[R] = -0.04f;
		p->colorchange[G] = -0.08f;
		p->colorchange[B] = -0.08f;
		p->birth = Engine.gameframes;
		p->death = p->birth + randomTime(30);
		p->gravity = TRUE;
		p->solid = TRUE;

	}while(--i);

}

/*
 * partTrail
 *
 *  Creates a simple particle trail. density per 1 unit level distance.
 */

void partTrail(vec3_t start, vec3_t end, float density)
{
	vec3_t	move, s, e;
	vec_t	dist;
	int		i;

	VectorCopy(start, s);
	VectorCopy(end, e);
	VectorSubtract(e, s, move);
	dist = (vec_t)VectorLength(move);
	i = (int)(dist * density);
	if(i < 1)
		return;
	VectorScale(move, (vec_t)1.0f / (vec_t)i, move);
	do
	{
		PARTICLE	*p;
	
		if(i < 0)
			return;

		p = partAdd();
		if(!p)
			return;
		p->size = 32.0f;
		VectorAdd(s, move, s);
		VectorCopy(s, p->center);
		randomMove(p->move, 0.05f);
		p->move[Z] += 0.1f;
		p->decay[X] = 0.0f;
		p->decay[Y] = 0.0f;
		p->decay[Z] = 0.0f;
		p->color[R] = 1.0f;
		p->color[G] = 1.0f;
		p->color[B] = 1.0f;
		p->colorchange[R] = 0.0f;
		p->colorchange[G] = 0.0f;
		p->colorchange[B] = 0.0f;
		p->birth = Engine.gameframes;
		p->death = p->birth + randomTime(30);
		p->gravity = FALSE;
		p->solid = FALSE;
	}while(--i);
}

void partMakeSplash(vec3_t center, int number, int type, vec3_t color)
{
	partExplosion(center, number);
}

void partMakeTrail(vec3_t start, vec3_t end, int type, vec3_t color)
{
	partTrail(start, end, 0.2f);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -