[particles] Create a psystem object

This takes care of the global variables to a point (there is still the
global struct shared between the non-vulkan renderers), but it also
takes care of glsl's points-only rendering.
This commit is contained in:
Bill Currie 2021-12-19 14:47:25 +09:00
parent 372c89b479
commit d70d72e6e4
17 changed files with 124 additions and 133 deletions

View file

@ -55,12 +55,14 @@ typedef struct particlectx_s {
VkPipelineLayout physics_layout;
VkPipelineLayout update_layout;
VkPipelineLayout draw_layout;
psystem_t psystem;
} particlectx_t;
struct cvar_s;
struct vulkan_ctx_s;;
struct r_particle_ctx_s *Vulkan_ParticleContext (struct vulkan_ctx_s *ctx);
struct psystem_s *Vulkan_ParticleSystem (struct vulkan_ctx_s *ctx);
void Vulkan_Particles_Init (struct vulkan_ctx_s *ctx);
void Vulkan_Particles_Shutdown (struct vulkan_ctx_s *ctx);
void Vulkan_DrawParticles (struct vulkan_ctx_s *ctx);

View file

@ -109,6 +109,7 @@ typedef struct vid_render_funcs_s {
float time);
void (*Fog_ParseWorldspawn) (struct plitem_s *worldspawn);
struct psystem_s *(*ParticleSystem) (void);
void (*R_Init) (void);
void (*R_RenderFrame) (SCR_Func *scr_funcs);
void (*R_ClearState) (void);

View file

@ -90,12 +90,15 @@ typedef struct partparm_s {
float alpha_rate;
} partparm_t;
// FIXME these really shouldn't be global, but they speed up particle creation
extern unsigned int r_maxparticles;
extern unsigned int numparticles;
extern struct particle_s *particles;
extern struct partparm_s *partparams;
extern const int **partramps;
typedef struct psystem_s {
uint32_t maxparticles;
uint32_t numparticles;
particle_t *particles;
partparm_t *partparams;
const int **partramps;
int points_only;
} psystem_t;
extern struct vid_render_funcs_s *r_funcs;
extern struct vid_render_data_s *r_data;

View file

@ -51,11 +51,17 @@ void R_InitEfrags (void);
void R_ClearState (void);
void R_InitSky (struct texture_s *mt); // called at level load
void R_Textures_Init (void);
void R_RunParticles (float dT);
void R_RenderView (void); // must set r_refdef first
void R_ViewChanged (void); // must set r_refdef first
// called whenever r_refdef or vid change
extern struct psystem_s r_psystem;
struct psystem_s *gl_ParticleSystem (void);
struct psystem_s *glsl_ParticleSystem (void);
struct psystem_s *sw_ParticleSystem (void);
struct psystem_s *sw32_ParticleSystem (void);
void R_RunParticles (float dT);
void R_AddEfrags (mod_brush_t *, entity_t *ent);
void R_RemoveEfrags (entity_t *ent);

View file

@ -46,6 +46,7 @@
#include "QF/sys.h"
#include "QF/va.h"
#include "QF/plugin/vid_render.h" //FIXME
#include "QF/scene/entity.h"
#include "compat.h"
@ -57,6 +58,7 @@ float cl_realtime;
cl_particle_funcs_t *clp_funcs;
static mtstate_t mt; // private PRNG state
static psystem_t *cl_psystem;
static cvar_t *easter_eggs;
static cvar_t *particles_style;
@ -116,12 +118,15 @@ inline static int
particle_new (ptype_t type, int texnum, vec4f_t pos, float scale,
vec4f_t vel, float live, int color, float alpha, float ramp)
{
if (numparticles >= r_maxparticles)
if (cl_psystem->numparticles >= cl_psystem->maxparticles) {
return 0;
particle_t *p = &particles[numparticles];
partparm_t *parm = &partparams[numparticles];
const int **rampptr = &partramps[numparticles];
numparticles += 1;
}
__auto_type ps = cl_psystem;
particle_t *p = &ps->particles[ps->numparticles];
partparm_t *parm = &ps->partparams[ps->numparticles];
const int **rampptr = &ps->partramps[ps->numparticles];
ps->numparticles += 1;
p->pos = pos;
p->vel = vel;
@ -216,14 +221,6 @@ add_particle (ptype_t type, vec4f_t pos, vec4f_t vel, float live, int color,
{
particle_new (type, part_tex_dot, pos, 1, vel, live, color, 1, ramp);
}
/*
void
CL_ClearParticles (void)
{
numparticles = 0;
}
*/
static void
pointfile_f (void)
@ -260,12 +257,10 @@ pointfile_f (void)
break;
c++;
if (numparticles >= r_maxparticles) {
if (!particle_new (pt_static, part_tex_dot, org, 1.5, zero,
99999, (-c) & 15, 1.0, 0.0)) {
Sys_MaskPrintf (SYS_dev, "Not enough free particles\n");
break;
} else {
particle_new (pt_static, part_tex_dot, org, 1.5, zero,
99999, (-c) & 15, 1.0, 0.0);
}
}
Qclose (f);
@ -276,8 +271,6 @@ static void
CL_ParticleExplosion_QF (vec4f_t org)
{
// CL_NewExplosion (org);
if (numparticles >= r_maxparticles)
return;
particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8,
5.0, (mtwist_rand (&mt) & 7) + 8,
0.5 + qfrandom (0.25), 0.0);
@ -288,11 +281,6 @@ CL_ParticleExplosion2_QF (vec4f_t org, int colorStart, int colorLength)
{
unsigned int i, j = 512;
if (numparticles >= r_maxparticles)
return;
else if (numparticles + j >= r_maxparticles)
j = r_maxparticles - numparticles;
for (i = 0; i < j; i++) {
particle_new_random (pt_blob, part_tex_dot, org, 16, 2, 256,
0.3,
@ -306,11 +294,6 @@ CL_BlobExplosion_QF (vec4f_t org)
unsigned int i;
unsigned int j = 1024;
if (numparticles >= r_maxparticles)
return;
else if (numparticles + j >= r_maxparticles)
j = r_maxparticles - numparticles;
for (i = 0; i < j >> 1; i++) {
particle_new_random (pt_blob, part_tex_dot, org, 12, 2, 256,
1.0 + (mtwist_rand (&mt) & 7) * 0.05,
@ -486,9 +469,6 @@ CL_TeleportSplash_QF (vec4f_t org)
static void
CL_RocketTrail_QF (vec4f_t start, vec4f_t end)
{
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -511,8 +491,6 @@ CL_RocketTrail_QF (vec4f_t start, vec4f_t end)
2.0 - percent * 2.0,
12 + (mtwist_rand (&mt) & 3),
0.5 + qfrandom (0.125) - percent * 0.40, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
pscale = pscalenext;
@ -522,9 +500,6 @@ CL_RocketTrail_QF (vec4f_t start, vec4f_t end)
static void
CL_GrenadeTrail_QF (vec4f_t start, vec4f_t end)
{
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -547,8 +522,6 @@ CL_GrenadeTrail_QF (vec4f_t start, vec4f_t end)
2.0 - percent * 2.0,
1 + (mtwist_rand (&mt) & 3),
0.625 + qfrandom (0.125) - percent * 0.40, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
pscale = pscalenext;
@ -558,9 +531,6 @@ CL_GrenadeTrail_QF (vec4f_t start, vec4f_t end)
static void
CL_BloodTrail_QF (vec4f_t start, vec4f_t end)
{
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -582,8 +552,6 @@ CL_BloodTrail_QF (vec4f_t start, vec4f_t end)
particle_new (pt_grav, part_tex_smoke, pos + roffs (4), pscale, vel,
2.0 - percent * 2.0,
68 + (mtwist_rand (&mt) & 3), 1.0, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
pscale = pscalenext;
@ -593,9 +561,6 @@ CL_BloodTrail_QF (vec4f_t start, vec4f_t end)
static void
CL_SlightBloodTrail_QF (vec4f_t start, vec4f_t end)
{
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -616,8 +581,6 @@ CL_SlightBloodTrail_QF (vec4f_t start, vec4f_t end)
particle_new (pt_grav, part_tex_smoke, pos + roffs (4), pscale, vel,
1.5 - percent * 1.5,
68 + (mtwist_rand (&mt) & 3), 0.75, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
pscale = pscalenext;
@ -629,9 +592,6 @@ CL_WizTrail_QF (vec4f_t start, vec4f_t end)
{
float dist = 3.0;
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -650,8 +610,6 @@ CL_WizTrail_QF (vec4f_t start, vec4f_t end)
30 * tracer_vel (tracercount++, vec),
0.5 - percent * 0.5,
52 + (mtwist_rand (&mt) & 4), 1.0 - percent * 0.125, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
}
@ -662,9 +620,6 @@ CL_FlameTrail_QF (vec4f_t start, vec4f_t end)
{
float dist = 3.0;
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -693,9 +648,6 @@ CL_VoorTrail_QF (vec4f_t start, vec4f_t end)
{
float dist = 3.0;
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -723,9 +675,6 @@ CL_GlowTrail_QF (vec4f_t start, vec4f_t end, int glow_color)
{
float dist = 3.0;
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -741,8 +690,6 @@ CL_GlowTrail_QF (vec4f_t start, vec4f_t end, int glow_color)
particle_new (pt_smoke, part_tex_dot, pos + roffs (5), 1.0, zero,
2.0 - percent * 0.2, glow_color, 1.0, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += step;
}
@ -754,8 +701,6 @@ CL_ParticleExplosion_EE (vec4f_t org)
/*
CL_NewExplosion (org);
*/
if (numparticles >= r_maxparticles)
return;
particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8,
5.0, mtwist_rand (&mt) & 255,
0.5 + qfrandom (0.25), 0.0);
@ -788,9 +733,6 @@ CL_TeleportSplash_EE (vec4f_t org)
static void
CL_RocketTrail_EE (vec4f_t start, vec4f_t end)
{
if (numparticles >= r_maxparticles)
return;
vec4f_t vec = end - start;
float maxlen = magnitudef (vec)[0];
vec = normalf (vec);
@ -811,8 +753,6 @@ CL_RocketTrail_EE (vec4f_t start, vec4f_t end)
2.0 - percent * 2.0,
mtwist_rand (&mt) & 255,
0.5 + qfrandom (0.125) - percent * 0.40, 0.0);
if (numparticles >= r_maxparticles)
break;
len += dist;
pos += len * vec;
pscale = pscalenext;
@ -1169,8 +1109,6 @@ CL_Particle_New (ptype_t type, int texnum, vec4f_t org, float scale,
vec4f_t vel, float live, int color, float alpha,
float ramp)
{
if (numparticles >= r_maxparticles)
return;
particle_new (type, texnum, org, scale, vel, live, color, alpha, ramp);
}
@ -1179,8 +1117,6 @@ CL_Particle_NewRandom (ptype_t type, int texnum, vec4f_t org,
int org_fuzz, float scale, int vel_fuzz, float live,
int color, float alpha, float ramp)
{
if (numparticles >= r_maxparticles)
return;
particle_new_random (type, texnum, org, org_fuzz, scale, vel_fuzz, live,
color, alpha, ramp);
}
@ -1321,6 +1257,7 @@ static void
particles_style_f (cvar_t *var)
{
easter_eggs_f (easter_eggs);
cl_psystem->points_only = !var->int_val;
}
static void
@ -1330,12 +1267,11 @@ CL_ParticleFunctionInit (void)
easter_eggs_f (easter_eggs);
}
/*
*/
void
CL_Particles_Init (void)
{
mtwist_seed (&mt, 0xdeadbeef);
cl_psystem = r_funcs->ParticleSystem ();
Cmd_AddCommand ("pointfile", pointfile_f,
"Load a pointfile to determine map leaks.");
easter_eggs = Cvar_Get ("easter_eggs", "0", CVAR_NONE, easter_eggs_f,

View file

@ -71,18 +71,18 @@ gl_R_InitParticles (void)
{
int i;
if (r_maxparticles && r_init) {
if (r_psystem.maxparticles && r_init) {
if (vaelements) {
partUseVA = 0;
pVAsize = r_maxparticles * 4;
pVAsize = r_psystem.maxparticles * 4;
Sys_MaskPrintf (SYS_dev,
"Particles: Vertex Array use disabled.\n");
} else {
if (vaelements > 3)
pVAsize = min ((unsigned int) (vaelements - (vaelements % 4)),
r_maxparticles * 4);
r_psystem.maxparticles * 4);
else if (vaelements >= 0)
pVAsize = r_maxparticles * 4;
pVAsize = r_psystem.maxparticles * 4;
Sys_MaskPrintf (SYS_dev,
"Particles: %i maximum vertex elements.\n",
pVAsize);
@ -137,8 +137,8 @@ gl_R_DrawParticles (void)
vacount = 0;
VA = particleVertexArray;
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
for (unsigned i = 0; i < r_psystem.numparticles; i++) {
particle_t *p = &r_psystem.particles[i];
// Don't render particles too close to us.
// Note, we must still do physics and such on them.
if (!(DotProduct (p->pos, vpn) < minparticledist)) {
@ -263,3 +263,9 @@ gl_R_Particles_Init_Cvars (void)
"Distance of the particle near clipping "
"plane from the player.");
}
psystem_t * __attribute__((const))//FIXME
gl_ParticleSystem (void)
{
return &r_psystem;
}

View file

@ -250,7 +250,7 @@ gl_R_RenderFrame (SCR_Func *scr_funcs)
time2 = Sys_DoubleTime ();
Sys_MaskPrintf (SYS_dev, "%3i ms %4i wpoly %4i epoly %4i parts\n",
(int) ((time2 - time1) * 1000), gl_c_brush_polys,
gl_c_alias_polys, numparticles);
gl_c_alias_polys, r_psystem.numparticles);
}
GL_FlushText ();

View file

@ -1,5 +1,5 @@
/*
gl_dyn_part.c
glsl_particles.c
OpenGL particle system.
@ -201,12 +201,13 @@ glsl_R_InitParticles (void)
if (particleVertexArray)
free (particleVertexArray);
particleVertexArray = calloc (r_maxparticles * 4, sizeof (partvert_t));
particleVertexArray = calloc (r_psystem.maxparticles * 4,
sizeof (partvert_t));
if (pVAindices)
free (pVAindices);
pVAindices = calloc (r_maxparticles * 6, sizeof (GLushort));
for (i = 0; i < r_maxparticles; i++) {
pVAindices = calloc (r_psystem.maxparticles * 6, sizeof (GLushort));
for (i = 0; i < r_psystem.maxparticles; i++) {
pVAindices[i * 6 + 0] = i * 4 + 0;
pVAindices[i * 6 + 1] = i * 4 + 1;
pVAindices[i * 6 + 2] = i * 4 + 2;
@ -256,8 +257,8 @@ draw_qf_particles (void)
vacount = 0;
VA = particleVertexArray;
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
for (unsigned i = 0; i < r_psystem.numparticles; i++) {
particle_t *p = &r_psystem.particles[i];
// Don't render particles too close to us.
// Note, we must still do physics and such on them.
if (!(DotProduct (p->pos, vpn) < minparticledist)) {
@ -375,8 +376,8 @@ draw_id_particles (void)
vacount = 0;
VA = particleVertexArray;
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
for (unsigned i = 0; i < r_psystem.numparticles; i++) {
particle_t *p = &r_psystem.particles[i];
// Don't render particles too close to us.
// Note, we must still do physics and such on them.
if (!(DotProduct (p->pos, vpn) < minparticledist)) {
@ -405,10 +406,10 @@ draw_id_particles (void)
void
glsl_R_DrawParticles (void)
{
if (!r_particles->int_val || !numparticles)
if (!r_particles->int_val || !r_psystem.numparticles)
return;
R_RunParticles (vr_data.frametime);
if (0/*FIXME r_particles_style->int_val*/) {
if (!r_psystem.points_only) {
draw_qf_particles ();
} else {
draw_id_particles ();
@ -448,3 +449,9 @@ glsl_R_Particles_Init_Cvars (void)
"Distance of the particle near clipping "
"plane from the player.");
}
psystem_t * __attribute__((const))//FIXME
glsl_ParticleSystem (void)
{
return &r_psystem;
}

View file

@ -36,10 +36,8 @@
#include "compat.h"
#include "r_internal.h"
unsigned int r_maxparticles, numparticles;
particle_t *particles;
partparm_t *partparams;
const int **partramps;
psystem_t r_psystem; //FIXME singleton
vec3_t r_pright, r_pup, r_ppn;
/*
@ -52,30 +50,31 @@ vec3_t r_pright, r_pup, r_ppn;
void
R_MaxParticlesCheck (cvar_t *r_particles, cvar_t *r_particles_max)
{
psystem_t *ps = &r_psystem;//FIXME
unsigned maxparticles = 0;
if (r_particles && r_particles->int_val) {
maxparticles = r_particles_max ? r_particles_max->int_val : 0;
}
if (r_maxparticles == maxparticles) {
if (ps->maxparticles == maxparticles) {
return;
}
size_t size = sizeof (particle_t) + sizeof (partparm_t)
+ sizeof (int *);
if (particles) {
Sys_Free (particles, r_maxparticles * size);
particles = 0;
partparams = 0;
partramps = 0;
if (ps->particles) {
Sys_Free (ps->particles, ps->maxparticles * size);
ps->particles = 0;
ps->partparams = 0;
ps->partramps = 0;
}
r_maxparticles = maxparticles;
ps->maxparticles = maxparticles;
if (r_maxparticles) {
particles = Sys_Alloc (r_maxparticles * size);
partparams = (partparm_t *) &particles[r_maxparticles];
partramps = (const int **) &partparams[r_maxparticles];
if (ps->maxparticles) {
ps->particles = Sys_Alloc (ps->maxparticles * size);
ps->partparams = (partparm_t *) &ps->particles[ps->maxparticles];
ps->partramps = (const int **) &ps->partparams[ps->maxparticles];
}
R_ClearParticles ();
}
@ -83,30 +82,32 @@ R_MaxParticlesCheck (cvar_t *r_particles, cvar_t *r_particles_max)
void
R_ClearParticles (void)
{
numparticles = 0;
psystem_t *ps = &r_psystem;//FIXME
ps->numparticles = 0;
}
void
R_RunParticles (float dT)
{
psystem_t *ps = &r_psystem;//FIXME
vec4f_t gravity = {0, 0, -vr_data.gravity, 0};
unsigned j = 0;
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
partparm_t *parm = &partparams[i];
for (unsigned i = 0; i < ps->numparticles; i++) {
particle_t *p = &ps->particles[i];
partparm_t *parm = &ps->partparams[i];
if (p->live <= 0 || p->ramp >= parm->ramp_max) {
continue;
}
const int *ramp = partramps[j];
const int *ramp = ps->partramps[j];
if (i > j) {
particles[j] = *p;
partparams[j] = *parm;
partramps[j] = ramp;
ps->particles[j] = *p;
ps->partparams[j] = *parm;
ps->partramps[j] = ramp;
}
p = &particles[j];
parm = &partparams[j];
p = &ps->particles[j];
parm = &ps->partparams[j];
j += 1;
p->pos += dT * p->vel;
@ -117,5 +118,5 @@ R_RunParticles (float dT)
p->icolor = ramp[(int)p->ramp];
}
}
numparticles = j;
ps->numparticles = j;
}

View file

@ -58,8 +58,8 @@ R_DrawParticles (void)
R_RunParticles (vr_data.frametime);
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
for (unsigned i = 0; i < r_psystem.numparticles; i++) {
particle_t *p = &r_psystem.particles[i];
D_DrawParticle (p);
}
}
@ -97,3 +97,9 @@ R_Particles_Init_Cvars (void)
"Distance of the particle near clipping "
"plane from the player.");
}
psystem_t * __attribute__((const))//FIXME
sw_ParticleSystem (void)
{
return &r_psystem;
}

View file

@ -61,8 +61,8 @@ sw32_R_DrawParticles (void)
R_RunParticles (vr_data.frametime);
for (unsigned i = 0; i < numparticles; i++) {
particle_t *p = &particles[i];
for (unsigned i = 0; i < r_psystem.numparticles; i++) {
particle_t *p = &r_psystem.particles[i];
sw32_D_DrawParticle (p);
}
}
@ -100,3 +100,9 @@ sw32_R_Particles_Init_Cvars (void)
"Distance of the particle near clipping "
"plane from the player.");
}
psystem_t * __attribute__((const))//FIXME
sw32_ParticleSystem (void)
{
return &r_psystem;
}

View file

@ -142,6 +142,7 @@ vid_render_funcs_t gl_vid_render_funcs = {
gl_Fog_Update,
gl_Fog_ParseWorldspawn,
gl_ParticleSystem,
gl_R_Init,
gl_R_RenderFrame,
gl_R_ClearState,

View file

@ -141,6 +141,7 @@ vid_render_funcs_t glsl_vid_render_funcs = {
glsl_Fog_Update,
glsl_Fog_ParseWorldspawn,
glsl_ParticleSystem,
glsl_R_Init,
glsl_R_RenderFrame,
glsl_R_ClearState,

View file

@ -138,6 +138,7 @@ vid_render_funcs_t sw_vid_render_funcs = {
0,
0,
sw_ParticleSystem,
sw_R_Init,
R_RenderFrame,
R_ClearState,

View file

@ -143,6 +143,7 @@ vid_render_funcs_t sw32_vid_render_funcs = {
0,
0,
sw32_ParticleSystem,
sw32_R_Init,
sw32_R_RenderFrame,
sw32_R_ClearState,

View file

@ -91,6 +91,12 @@ vulkan_Fog_ParseWorldspawn (struct plitem_s *worldspawn)
{
}
static struct psystem_s *
vulkan_ParticleSystem (void)
{
return Vulkan_ParticleSystem (vulkan_ctx);
}
static void
vulkan_R_Init (void)
{
@ -663,6 +669,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = {
vulkan_Fog_Update,
vulkan_Fog_ParseWorldspawn,
vulkan_ParticleSystem,
vulkan_R_Init,
vulkan_R_RenderFrame,
vulkan_R_ClearState,

View file

@ -125,3 +125,9 @@ Vulkan_Particles_Shutdown (vulkan_ctx_t *ctx)
free (pctx->frames.a);
free (pctx);
}
psystem_t *__attribute__((pure))//FIXME?
Vulkan_ParticleSystem (vulkan_ctx_t *ctx)
{
return &ctx->particle_context->psystem; //FIXME support more
}