Particle System

(von Basiror - nicht übersetzt.)
Ok let`s start with adding our project files. Create rf_particle source, rf_particle and rf_particle_structs header files. Now we create a class that handles the rendering and all the stuff.

class CWeatherSystem
{
public:
CWeatherSystem();
virtual void Precache(void);
virtual void Render(void);
virtual void InitParticles(int iCount,int iCategory);
virtual void Relocate(part_s *particle);
float size;

HSPRITE hWeather;

};

In the particle structs header you add the definition for our particles. It should look like the following

typedef struct part_s
{
vec3_t origin;
float vel;
struct part_s *next;
}part_t;

Now we jump into our source file and add all the needed headers and we set up the particle pointer that holds our linked list.

#include "hud.h"
#include "cl_util.h"
#include "const.h"
#include "entity_state.h"
#include "cl_entity.h"
#include "triangleapi.h"
#include "r_studioint.h"
#include "pmtrace.h"
#include "pm_defs.h"
#include "rf_particle.h"
#define PEF_SNOW 1
#define PEF_RAIN 2

part_t *pPart;

Ok new we add the constructor of the class and the rest of the functions except the Render() function, because i need to explain it a bit more than the rest.

CWeatherSystem::CWeatherSystem()
{
size = 2.5;//this is case sensitive
pPart =NULL;
hWeather = 0;
InitParticles(300,PEF_SNOW);
}

void CWeatherSystem::Precache(void)
{
//this function is planed for loading the sprites only ones
//but i am not sure if i only need to load them once or every frame
}

//this generates a linked list with random x y z coordinates of the origin
void CWeatherSystem::InitParticles(int iCount, int iCategory)
{
part_t *pNext;
for(int i=1;i<=iCount;i++)
{
pNext = (part_t*)malloc(sizeof *pNext);//new part_t;

pNext->origin[0] = gEngfuncs.pfnRandomFloat( -400.0, 400.0 );
pNext->origin[1] = gEngfuncs.pfnRandomFloat( -400.0, 400.0 );
pNext->origin[2] = gEngfuncs.pfnRandomFloat( 256.0, 300.0 );
//units above the player
pNext->vel = gEngfuncs.pfnRandomFloat( 1.0, 1.9 );
pNext->next = pPart;
pPart = pNext;
}
}


//this is called everytime a particle collides with a wall
void CWeatherSystem::Relocate(part_s *particle)
{
particle->origin[0] = gEngfuncs.pfnRandomFloat( -400.0, 400.0 );
particle->origin[1] = gEngfuncs.pfnRandomFloat( -400.0, 400.0 );
particle->origin[2] = gEngfuncs.pfnRandomFloat( 256.0, 300.0 );
//units above the player
particle->vel = gEngfuncs.pfnRandomFloat( 0.9, 1.7 );
}

Ok so far so good, now comes the render part, I hope it isn`t too confusing.
void CWeatherSystem::Render(void)
{
vec3_t normal,forward,right,up,point,origin,test[4];
//Needed local variables

gEngfuncs.GetViewAngles((float*)normal);
//Gets the players view angle

AngleVectors(normal,forward,right,up);
//Sets the forward right and up angles
part_t *pRender = pPart;//needed
if(pRender==NULL)//don t render if there is nothing to render
return;

cl_entity_t *ent = gEngfuncs.GetLocalPlayer();
//need this for the players origin

if (hWeather == 0)
{
char sz[256];
sprintf( sz, "sprites/snow.spr" );
hWeather = SPR_Load( sz );
}
if(!gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.
GetSpritePointer(hWeather ),0 ))
{
return;
}
gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd);
gEngfuncs.pTriAPI->CullFace(TRI_NONE);
while(pRender)
{
origin=ent->origin + pRender->origin;
pRender->origin[2]= pRender->origin[2] - pRender->vel;
test[0]=test[1]=test[2]=test[3]=origin;
test[0][2]+=2;//collision detection
test[1][2]+=1;//collision detection
test[2][2]+=1.5;//collision detection
test[3][2]+=0.5;//collision detection

if(gEngfuncs.PM_PointContents( origin, NULL )==CONTENTS_SKY ||(
gEngfuncs.PM_PointContents( test[0], NULL )!=CONTENTS_SOLID &&
gEngfuncs.PM_PointContents( test[1], NULL )!=CONTENTS_SOLID &&
gEngfuncs.PM_PointContents( test[2], NULL )!=CONTENTS_SOLID&&
gEngfuncs.PM_PointContents( test[3], NULL )!=CONTENTS_SOLID))
{
gEngfuncs.pTriAPI->Begin( TRI_QUADS );

gEngfuncs.pTriAPI->TexCoord2f (0, 0);//new vertex
VectorMA ( origin,size ,up ,point);
VectorMA (point ,-size ,right ,point);
gEngfuncs.pTriAPI->Vertex3fv(point);


gEngfuncs.pTriAPI->TexCoord2f (0, 1);//new vertex
VectorMA (origin,size,up,point);
VectorMA (point,size,right,point);
gEngfuncs.pTriAPI->Vertex3fv (point);


gEngfuncs.pTriAPI->TexCoord2f (1, 1);//new vertex
VectorMA (origin,-size,up,point);
VectorMA (point,size,right,point);
gEngfuncs.pTriAPI->Vertex3fv (point);


gEngfuncs.pTriAPI->TexCoord2f (1, 0);//new vertex
VectorMA (origin,-size,up,point);
VectorMA (point,-size,right,point);
gEngfuncs.pTriAPI->Vertex3fv (point);
gEngfuncs.pTriAPI->End();
}
else
Relocate(pRender);

if(pRender->origin[2]<=-256)
Relocate(pRender);

pRender=pRender->next;
}
gEngfuncs.pTriAPI->RenderMode(kRenderNormal);


}

And now we install it

//In cdll_int.cpp add the pointer
CWeatherSystem *g_pParticleSys;

//In the same file in hud int function create the system
int DLLEXPORT HUD_Init( void )
{
InitInput();
gHUD.Init();
Scheme_Init();
//RF
//g_pParticleSys = new CMainSystem();
//RF
g_pParticleSys = new CWeatherSystem();
return 1;
}
//Add to the top of tri.cpp
extern CWeatherSystem *g_pParticleSys;

//Add this to one of the Render functions of tri cpp
if(g_pParticleSys)
g_pParticleSys->Render();

I think this piece of code was commented well enough. Here are two functions i have written maybe someone can make any use out of them, the second one needs a bu fix, but i dont fix this now cause you don t need it for the tutorial

void ViewAngleCalc (const float *v_angle, float *v_dir)
{
if(!v_angle)
return;
float x,y,angle;
angle=v_angle[1];
if(v_angle[1]==0)
{
x=1;
y=0;
}
else if(v_angle[1]==-90)
{
x=0;
y=1;
}
else if(v_angle[1]==90)
{
x=0;
y=-1;
}
else if((v_angle[1]==-180)||(v_angle[1]==180))
{
x=-1;
y=0;
}

if((v_angle[1]<0)&&(v_angle[1]>-90))
{
angle*=-1;
x=cos(angle);
y=sin(angle);
}
else if((v_angle[1]<-90)&&(v_angle[1]>-180))
{
angle*=-1;
angle=180-angle;
x=-cos(angle);
y=sin(angle);
}
else if((v_angle[1]>0)&&(v_angle[1]<90))
{
x=cos(angle);
y=-sin(angle);
}
else if((v_angle[1]>90)&&(v_angle[1]<180))
{
angle=180-angle;
x=-cos(angle);
y=-sin(angle);
}
v_dir[0]=x;
v_dir[1]=y;
v_dir[2]=0;
}

bool SameQuadrant(const float angle, const float *v_comp2)
{
if(!angle||!v_comp2)
return FALSE;

if( (angle<=0) && (angle>=-90) && (v_comp2[0]>=0) && (v_comp2[1]>=0))
return TRUE;
else if( (angle<=-90) && (angle>=-180) && (v_comp2[0]<=0) && (v_comp2[1]>=0))
return TRUE;
else if( (angle>=0) && (angle<=90) && (v_comp2[0]<=0) && (v_comp2[1]<=0))
return TRUE;
else if( (angle>=90) && (angle<=180) && (v_comp2[0]>=0) && (v_comp2[1]<=0))
return TRUE;
else return FALSE;
}
Die Verwendung aller Dokumente einschließlich der Abbildungen ausschließlich zu nichtkommerziellen Zwecken. Verbreitung des Dokuments auf Speichermedien, (insbesondere auf CD-ROMs als Beilage zu Zeitschriften und Magazinen oder sog. "Mission-Packs" etc.) ist untersagt.
 
half-life/tutorials/particle-system.txt · Zuletzt geändert: 2005/05/16 14:54 von Flow