📄 particle.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 + -