[renderer] Get trails rendering again

They're not quite working (trail path offset is incorrect) but their
pixels are getting to the screen. Also, lifetimes are off for rocket
trails in that as soon as the entity dies, so does the trail.
This commit is contained in:
Bill Currie 2023-10-06 10:31:12 +09:00
parent ef6b10afb1
commit 34daf9032d
19 changed files with 463 additions and 305 deletions

View file

@ -44,4 +44,8 @@ void glsl_R_Particles_Init_Cvars (void);
void glsl_R_InitParticles (void); void glsl_R_InitParticles (void);
void glsl_R_ShutdownParticles (void); void glsl_R_ShutdownParticles (void);
void glsl_R_InitTrails (void);
void glsl_R_ShutdownTrails (void);
void glsl_R_DrawTrails (struct psystem_s *psystem);
#endif//__QF_GLSL_qf_particles_h #endif//__QF_GLSL_qf_particles_h

View file

@ -118,6 +118,7 @@ typedef struct vid_render_funcs_s {
void (*Draw_Glyph) (int x, int y, int fontid, int glyphid, int c); void (*Draw_Glyph) (int x, int y, int fontid, int glyphid, int c);
struct psystem_s *(*ParticleSystem) (void); struct psystem_s *(*ParticleSystem) (void);
struct psystem_s *(*TrailSystem) (void);
void (*R_Init) (void); void (*R_Init) (void);
void (*R_ClearState) (void); void (*R_ClearState) (void);
void (*R_LoadSkys) (const char *); void (*R_LoadSkys) (const char *);
@ -127,6 +128,7 @@ typedef struct vid_render_funcs_s {
void (*begin_frame) (void); void (*begin_frame) (void);
void (*render_view) (void); void (*render_view) (void);
void (*draw_particles) (struct psystem_s *psystem); void (*draw_particles) (struct psystem_s *psystem);
void (*draw_trails) (struct psystem_s *psystem);
void (*draw_transparent) (void); void (*draw_transparent) (void);
void (*post_process) (struct framebuffer_s *src); void (*post_process) (struct framebuffer_s *src);
void (*set_2d) (int scaled); void (*set_2d) (int scaled);

View file

@ -41,10 +41,8 @@ typedef enum {
part_tex_smoke, part_tex_smoke,
} ptextype_t; } ptextype_t;
typedef struct particle_s particle_t;
// !!! if this is changed, it must be changed in d_ifacea.h too !!! // !!! if this is changed, it must be changed in d_ifacea.h too !!!
struct particle_s { typedef struct particle_s {
vec4f_t pos; vec4f_t pos;
vec4f_t vel; vec4f_t vel;
@ -61,7 +59,24 @@ struct particle_s {
float ramp; float ramp;
float scale; float scale;
float live; float live;
}; } particle_t;
static_assert (sizeof (particle_t) == 4 * sizeof(vec4f_t),
"particle_t wrong size");
typedef struct trailpnt_s {
vec4f_t pos;
vec4f_t vel;
vec3_t bary;
float pathoffset;
byte colora[4];
byte colorb[4];
uint32_t trailid;
float live;
} trailpnt_t;
static_assert (sizeof (trailpnt_t) == 4 * sizeof(vec4f_t),
"trailprt_t wrong size");
typedef struct partparm_s { typedef struct partparm_s {
vec4f_t drag; // drag[3] is grav scale vec4f_t drag; // drag[3] is grav scale
@ -71,6 +86,9 @@ typedef struct partparm_s {
float alpha_rate; float alpha_rate;
} partparm_t; } partparm_t;
static_assert (sizeof (partparm_t) == 2 * sizeof(vec4f_t),
"partparm_t wrong size");
typedef struct psystem_s { typedef struct psystem_s {
vec4f_t gravity; vec4f_t gravity;
uint32_t maxparticles; uint32_t maxparticles;
@ -186,4 +204,9 @@ void Fog_StartAdditive (void);
void Fog_StopAdditive (void); void Fog_StopAdditive (void);
void Fog_Init (void); void Fog_Init (void);
bool R_Trail_Valid (psystem_t *system, uint32_t trailid) __attribute__((pure));
uint32_t R_Trail_Create (psystem_t *system, int num_points, vec4f_t start);
void R_Trail_Update (psystem_t *system, uint32_t trailid, vec4f_t pos);
void R_Trail_Destroy (psystem_t *system, uint32_t trailid);
#endif//__QF_render_h #endif//__QF_render_h

View file

@ -75,7 +75,7 @@ typedef struct visibility_s {
typedef struct renderer_s { typedef struct renderer_s {
struct model_s *model; // NULL = no model struct model_s *model; // NULL = no model
struct skin_s *skin; struct skin_s *skin;
struct trail_s *trail; // FIXME should be own component struct trail_s *trail;
unsigned fullbright:1; unsigned fullbright:1;
unsigned noshadows:1; unsigned noshadows:1;
unsigned onlyshadows:1; unsigned onlyshadows:1;

View file

@ -36,6 +36,7 @@
enum { enum {
effect_light, // light entity id effect_light, // light entity id
effect_muzzleflash, // light entity id effect_muzzleflash, // light entity id
effect_trail, // trail id
effect_comp_count, effect_comp_count,
}; };
@ -54,5 +55,6 @@ void CL_EntityEffects (struct entity_s ent, struct entity_state_s *state,
double time); double time);
void CL_MuzzleFlash (struct entity_s ent, vec4f_t position, vec4f_t fv, void CL_MuzzleFlash (struct entity_s ent, vec4f_t position, vec4f_t fv,
float zoffset, double time); float zoffset, double time);
void CL_Effects_Init (void);
#endif//__client_effects_h #endif//__client_effects_h

View file

@ -45,16 +45,13 @@ typedef enum {
struct entity_s; struct entity_s;
void R_Particles_Init_Cvars (void); void R_Trails_Init (void);
void R_Particle_New (const char *type, int texnum, const vec3_t org, void R_Trails_Init_Cvars (void);
float scale, const vec3_t vel, float die, int color, void R_ClearTrails (void);
float alpha, float ramp); void R_RunTrails (float dT);
void R_Particle_NewRandom (const char *type, int texnum, const vec3_t org,
int org_fuzz, float scale, int vel_fuzz, float die,
int color, float alpha, float ramp);
void R_InitBubble (void);
void R_InitParticles (void); void R_RunParticles (float dT);
void R_Particles_Init_Cvars (void);
void R_ClearParticles (void); void R_ClearParticles (void);
void R_InitSprites (void); void R_InitSprites (void);

View file

@ -42,10 +42,11 @@ void R_ViewChanged (void); // must set r_refdef first
// called whenever r_refdef or vid change // called whenever r_refdef or vid change
extern struct psystem_s r_psystem; extern struct psystem_s r_psystem;
extern struct psystem_s r_tsystem;
struct psystem_s *gl_ParticleSystem (void); struct psystem_s *gl_ParticleSystem (void);
struct psystem_s *glsl_ParticleSystem (void); struct psystem_s *glsl_ParticleSystem (void);
struct psystem_s *glsl_TrailSystem (void);
struct psystem_s *sw_ParticleSystem (void); struct psystem_s *sw_ParticleSystem (void);
void R_RunParticles (float dT);
struct scene_s; struct scene_s;
void R_NewScene (struct scene_s *scene); void R_NewScene (struct scene_s *scene);

View file

@ -53,6 +53,15 @@
ecs_system_t effect_system; ecs_system_t effect_system;
static psystem_t *cl_tsystem;
static void
cl_destroy_trail (void *comp)
{
auto trail = *(uint32_t *) comp;
R_Trail_Destroy (cl_tsystem, trail);
}
const component_t effect_components[effect_comp_count] = { const component_t effect_components[effect_comp_count] = {
[effect_light] = { [effect_light] = {
.size = sizeof (uint32_t), .size = sizeof (uint32_t),
@ -62,9 +71,15 @@ const component_t effect_components[effect_comp_count] = {
.size = sizeof (uint32_t), .size = sizeof (uint32_t),
.name = "muzzle flash", .name = "muzzle flash",
}, },
[effect_trail] = {
.size = sizeof (uint32_t),
.name = "effect trail",
.destroy = cl_destroy_trail,
},
}; };
#define c_light (effect_system.base + effect_light) #define c_light (effect_system.base + effect_light)
#define c_trail (effect_system.base + effect_trail)
static bool static bool
has_light (entity_t ent) has_light (entity_t ent)
@ -98,6 +113,27 @@ attach_light_ent (entity_t ent)
return light; return light;
} }
static bool
has_trail (entity_t ent)
{
return Ent_HasComponent (ent.id, c_trail, ent.reg);
}
static uint32_t
get_trail (entity_t ent)
{
if (!has_trail (ent)) {
return nullent;
}
return *(uint32_t *) Ent_GetComponent (ent.id, c_trail, ent.reg);
}
static void
set_trail (entity_t ent, uint32_t trail)
{
Ent_SetComponent (ent.id, c_trail, ent.reg, &trail);
}
void void
CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size, CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size,
byte glow_color, double time) byte glow_color, double time)
@ -181,6 +217,14 @@ CL_ModelEffects (entity_t ent, int glow_color, double time)
}); });
Light_LinkLight (cl_world.scene->lights, light); Light_LinkLight (cl_world.scene->lights, light);
clp_funcs->RocketTrail (*old_origin, ent_origin); clp_funcs->RocketTrail (*old_origin, ent_origin);
if (cl_tsystem) {
uint32_t trail = get_trail (ent);
if (R_Trail_Valid (cl_tsystem, trail)) {
R_Trail_Update (cl_tsystem, trail, ent_origin);
} else {
set_trail (ent, R_Trail_Create (cl_tsystem, 30, ent_origin));
}
}
renderer->noshadows = 1; renderer->noshadows = 1;
} else if (model->effects & ME_GRENADE) } else if (model->effects & ME_GRENADE)
clp_funcs->GrenadeTrail (*old_origin, ent_origin); clp_funcs->GrenadeTrail (*old_origin, ent_origin);
@ -210,3 +254,11 @@ CL_EntityEffects (entity_t ent, entity_state_t *state, double time)
CL_MuzzleFlash (ent, position, fv, 16, time); CL_MuzzleFlash (ent, position, fv, 16, time);
} }
} }
void
CL_Effects_Init (void)
{
if (r_funcs->TrailSystem) {
cl_tsystem = r_funcs->TrailSystem ();
}
}

View file

@ -58,9 +58,10 @@ libs_video_renderer_libQFrenderer_la_SOURCES=\
libs/video/renderer/r_light.c \ libs/video/renderer/r_light.c \
libs/video/renderer/r_main.c \ libs/video/renderer/r_main.c \
libs/video/renderer/r_part.c \ libs/video/renderer/r_part.c \
libs/video/renderer/r_progs.c \
libs/video/renderer/r_scrap.c \ libs/video/renderer/r_scrap.c \
libs/video/renderer/r_screen.c \ libs/video/renderer/r_screen.c \
libs/video/renderer/r_progs.c libs/video/renderer/r_trails.c
video_renderer_gl_libs= \ video_renderer_gl_libs= \
libs/video/renderer/librender_gl.la \ libs/video/renderer/librender_gl.la \

View file

@ -186,6 +186,7 @@ glsl_R_Init (void)
glsl_R_InitIQM (); glsl_R_InitIQM ();
glsl_R_InitSprites (); glsl_R_InitSprites ();
glsl_R_InitParticles (); glsl_R_InitParticles ();
glsl_R_InitTrails ();
glsl_InitFisheye (); glsl_InitFisheye ();
glsl_InitWarp (); glsl_InitWarp ();
Skin_Init (); Skin_Init ();

View file

@ -87,9 +87,8 @@ static const char *particle_trail_debug_frag_effects[] =
0 0
}; };
static struct { typedef struct {
int program; int program;
int debug_program;
shaderparam_t proj; shaderparam_t proj;
shaderparam_t view; shaderparam_t view;
shaderparam_t viewport; shaderparam_t viewport;
@ -101,8 +100,10 @@ static struct {
shaderparam_t texoff; shaderparam_t texoff;
shaderparam_t colora; shaderparam_t colora;
shaderparam_t colorb; shaderparam_t colorb;
} trail = { } trailprog_t;
0, 0,
static trailprog_t trail = {
0,
{"projection_mat", 1}, {"projection_mat", 1},
{"view_mat", 1}, {"view_mat", 1},
{"viewport", 1}, {"viewport", 1},
@ -115,62 +116,16 @@ static struct {
{"vcolora", 0}, {"vcolora", 0},
{"vcolorb", 0}, {"vcolorb", 0},
}; };
static trailprog_t trail_debug;
typedef struct point_s {
particle_t p;
struct point_s *next;
} point_t;
typedef struct trail_s {
struct trail_s *next;
struct trail_s **prev;
struct trail_s **owner;
point_t *points;
point_t **head; // new points are appended to the list
int num_points;
} trail_t;
typedef struct trailvtx_s { typedef struct trailvtx_s {
quat_t vertex; vec4f_t vertex;
vec3_t bary; vec3_t bary;
float texoff; float texoff;
quat_t colora; byte colora[4];
quat_t colorb; byte colorb[4];
} trailvtx_t; } trailvtx_t;
ALLOC_STATE (trail_t, trails);
ALLOC_STATE (point_t, points);
static trail_t *trails_active;
static trail_t *
new_trail (void)
{
trail_t *trail;
ALLOC (16, trail_t, trails, trail);
trail->head = &trail->points;
return trail;
}
static void
free_trail (trail_t *trail)
{
FREE (trails, trail);
}
static point_t *
new_point (void)
{
point_t *point;
ALLOC (128, point_t, points, point);
return point;
}
static void
free_point (point_t *point)
{
FREE (points, point);
}
static void static void
alloc_arrays (psystem_t *ps) alloc_arrays (psystem_t *ps)
{ {
@ -197,20 +152,38 @@ alloc_arrays (psystem_t *ps)
} }
void void
glsl_R_ShutdownParticles (void) glsl_R_ShutdownTrails (void)
{ {
free (particleVertexArray); free (particleVertexArray);
free (pVAindices); free (pVAindices);
} }
static void
build_program (trailprog_t *prog, const char *name, int vert, int frag)
{
prog->program = GLSL_LinkProgram (name, vert, frag);
GLSL_ResolveShaderParam (prog->program, &prog->proj);
GLSL_ResolveShaderParam (prog->program, &prog->view);
GLSL_ResolveShaderParam (prog->program, &prog->viewport);
GLSL_ResolveShaderParam (prog->program, &prog->width);
GLSL_ResolveShaderParam (prog->program, &prog->last);
GLSL_ResolveShaderParam (prog->program, &prog->current);
GLSL_ResolveShaderParam (prog->program, &prog->next);
GLSL_ResolveShaderParam (prog->program, &prog->barycentric);
GLSL_ResolveShaderParam (prog->program, &prog->texoff);
GLSL_ResolveShaderParam (prog->program, &prog->colora);
GLSL_ResolveShaderParam (prog->program, &prog->colorb);
}
void void
glsl_R_InitParticles (void) glsl_R_InitTrails (void)
{ {
shader_t *vert_shader, *frag_shader, *debug_shader; shader_t *vert_shader, *frag_shader, *debug_shader;
int vert; int vert;
int frag; int frag;
int debug; int debug;
vert_shader = GLSL_BuildShader (particle_trail_vert_effects); vert_shader = GLSL_BuildShader (particle_trail_vert_effects);
frag_shader = GLSL_BuildShader (particle_trail_frag_effects); frag_shader = GLSL_BuildShader (particle_trail_frag_effects);
debug_shader = GLSL_BuildShader (particle_trail_debug_frag_effects); debug_shader = GLSL_BuildShader (particle_trail_debug_frag_effects);
@ -218,270 +191,143 @@ glsl_R_InitParticles (void)
frag = GLSL_CompileShader ("trail.frag", frag_shader, GL_FRAGMENT_SHADER); frag = GLSL_CompileShader ("trail.frag", frag_shader, GL_FRAGMENT_SHADER);
debug = GLSL_CompileShader ("trail.frag.debug", debug_shader, debug = GLSL_CompileShader ("trail.frag.debug", debug_shader,
GL_FRAGMENT_SHADER); GL_FRAGMENT_SHADER);
trail.program = GLSL_LinkProgram ("trail", vert, frag); trail_debug = trail;
trail.debug_program = GLSL_LinkProgram ("trail.debug", vert, debug); build_program (&trail, "trail", vert, frag);
build_program (&trail_debug, "trail.debug", vert, debug);
GLSL_ResolveShaderParam (trail.program, &trail.proj);
GLSL_ResolveShaderParam (trail.program, &trail.view);
GLSL_ResolveShaderParam (trail.program, &trail.viewport);
GLSL_ResolveShaderParam (trail.program, &trail.width);
GLSL_ResolveShaderParam (trail.program, &trail.last);
GLSL_ResolveShaderParam (trail.program, &trail.current);
GLSL_ResolveShaderParam (trail.program, &trail.next);
GLSL_ResolveShaderParam (trail.program, &trail.barycentric);
GLSL_ResolveShaderParam (trail.program, &trail.texoff);
GLSL_ResolveShaderParam (trail.program, &trail.colora);
GLSL_ResolveShaderParam (trail.program, &trail.colorb);
GLSL_FreeShader (vert_shader); GLSL_FreeShader (vert_shader);
GLSL_FreeShader (frag_shader); GLSL_FreeShader (frag_shader);
GLSL_FreeShader (debug_shader);
alloc_arrays (&r_psystem); alloc_arrays (&r_psystem);
} }
static void static int
add_trail_to_ent (entity_t ent) count_bits (uint32_t v)
{ {
renderer_t *r = Ent_GetComponent (ent.id, scene_renderer, ent.reg); int c = 0;
r->trail = new_trail (); for (; v; c++) {
r->trail->next = trails_active; v &= v - 1;
r->trail->prev = &trails_active; }
r->trail->owner = &r->trail; return c;
if (trails_active)
trails_active->prev = &r->trail->next;
trails_active = r->trail;
} }
static inline point_t *
new_trail_point (vec4f_t origin, float pscale, float percent)
{
point_t *point;
//int ramp;
point = new_point (); static int
*point = (point_t) { count_points (uint32_t block_mask)
.p.pos = origin, {
.p.color = (vec4f_t) {1,1,1,1},//ramp3[ramp = mtwist_rand (&mt) & 3],XXX int num_blocks = count_bits (block_mask);
.p.tex = part_tex_smoke, return num_blocks * 64;
.p.scale = pscale + percent * 4.0, }
.p.alpha = 0.5 + qfrandom (0.125) - percent * 0.40,
.p.vel = {}, static void
.p.live = 2.0 - percent * 2.0, build_verts (trailvtx_t *verts, int *counts,
// .p.ramp = ramp,XXX const trailpnt_t *points, uint32_t block_mask)
// .p.physics = R_ParticlePhysics ("pt_float"),XXX pt_static for debug {
uint32_t id = ~0u;
for (int m = 0; m < 32; m++, points += 64) {
if (!(block_mask & (1 << m))) {
if (*counts) {
counts++;
}
continue;
}
if (id != ~0u && points->trailid != id) {
counts++;
}
id = points->trailid;
*counts += 64;
for (int i = 0; i < 64; i++) {
verts[i] = (trailvtx_t) {
.vertex = points[i].pos,
.bary = {VectorExpand (points[i].bary)},
.texoff = points[i].pathoffset,
.colora = { QuatExpand (points[i].colora)},
.colorb = { QuatExpand (points[i].colorb)},
}; };
return point;
} }
verts += 64;
static inline void
add_point_to_trail (trail_t *trail, point_t *point)
{
*trail->head = point;
trail->head = &point->next;
trail->num_points++;
}
static void __attribute__((used))//XXX
R_RocketTrail_trail (entity_t ent)
{
transform_t transform = Entity_Transform (ent);
renderer_t *renderer = Ent_GetComponent (ent.id, scene_renderer, ent.reg);
vec4f_t *old_origin = Ent_GetComponent (ent.id, scene_old_origin, ent.reg);
vec4f_t ent_origin = Transform_GetWorldPosition (transform);
vec4f_t vec = ent_origin - *old_origin;
float maxlen = magnitudef (vec)[0];
vec /= maxlen;
if (!renderer->trail) {
add_trail_to_ent (ent);
}
trail_t *trail = renderer->trail;
float origlen = vr_data.frametime / maxlen;
float pscale = 1.5 + qfrandom (1.5);
vec4f_t pos = *old_origin;
float len = 0.0;
while (len < maxlen) {
float pscalenext = 1.5 + qfrandom (1.5);
float dist = (pscale + pscalenext) * 3.0;
float percent = len * origlen;
point_t *point = new_trail_point (pos, pscale, percent);
add_point_to_trail (trail, point);
len += dist;
pos += dist * vec;
pscale = pscalenext;
}
}
static inline void
set_vertex (trailvtx_t *v, const point_t *point, float w, const vec3_t bary,
float off)
{
VectorCopy (point->p.pos, v->vertex);
VectorCopy (bary, v->bary);
v->vertex[3] = w * point->p.scale;// just w for debug
v->texoff = off;
VectorCopy (point->p.color, v->colora);
v->colora[3] = point->p.alpha * 1.2;
QuatSet (-1, -1, -1, -0.5, v->colorb);
}
static void
count_points (int *num_verts)
{
trail_t *trail;
*num_verts = 0;
for (trail = trails_active; trail; trail = trail->next) {
if (trail->num_points < 2)
continue;
// Each point has two vertices, thus the * 2. However, both the
// first point and the last point need to be duplicated so the vertex
// shader has valid data, thus need vertices for two extra points.
*num_verts += (trail->num_points + 2) * 2;
} }
} }
static void static void
build_verts (trailvtx_t *v) draw_trails (trailpnt_t *points, uint32_t block_mask)
{ {
trail_t *trail; int num_verts = count_points (block_mask);
point_t *point, *last_point = 0, *second_last_point = 0; if (!num_verts) {
point_t dup;
float bary[] = {0, 0, 1, 0, 0, 1, 0, 0};
int bind = 0;
memset (&dup, 0, sizeof (dup));
for (trail = trails_active; trail; trail = trail->next) {
int index = 0;
if (trail->num_points < 2)
continue;
point = trail->points;
dup.p.pos = 2 * point->p.pos;
dup.p.pos -= point->next->p.pos;
set_vertex (v++, &dup, -1, bary, 0);
set_vertex (v++, &dup, +1, bary, 0);
for (point = trail->points; point; point = point->next) {
second_last_point = last_point;
last_point = point;
set_vertex (v++, point, -1, bary + bind++, index);
set_vertex (v++, point, +1, bary + bind++, index);
bind %= 3;
index++;
R_RunParticlePhysics (&point->p);
}
dup.p.pos = 2 * last_point->p.pos;
dup.p.pos -= second_last_point->p.pos;
set_vertex (v++, &dup, -1, bary, 0);
set_vertex (v++, &dup, +1, bary, 0);
}
}
static void
expire_trails (void)
{
trail_t *trail, *next_trail;
for (trail = trails_active; trail; trail = next_trail) {
next_trail = trail->next;
while (trail->points && trail->points->p.live <= 0) {
point_t *point = trail->points;
trail->points = point->next;
free_point (point);
trail->num_points--;
}
if (trail->num_points < 2) {
if (trail->next)
trail->next->prev = trail->prev;
*trail->prev = trail->next;
*trail->owner = 0;
free_trail (trail);
}
}
}
static void
draw_trails (void)
{
trail_t *trl;
int num_verts;
int first;
trailvtx_t *verts;
count_points (&num_verts);
if (!num_verts)
return; return;
}
verts = alloca (num_verts * sizeof (trailvtx_t)); trailvtx_t verts[num_verts];
build_verts (verts); int counts[33] = {};
build_verts (verts, counts, points, block_mask);
qfeglUseProgram (trail.program); auto prog = trail;
qfeglEnableVertexAttribArray (trail.last.location); qfeglUseProgram (prog.program);
qfeglEnableVertexAttribArray (trail.current.location); qfeglEnableVertexAttribArray (prog.last.location);
qfeglEnableVertexAttribArray (trail.next.location); qfeglEnableVertexAttribArray (prog.current.location);
if (trail.barycentric.location >= 0) qfeglEnableVertexAttribArray (prog.next.location);
qfeglEnableVertexAttribArray (trail.barycentric.location); if (prog.barycentric.location >= 0)
qfeglEnableVertexAttribArray (trail.texoff.location); qfeglEnableVertexAttribArray (prog.barycentric.location);
qfeglEnableVertexAttribArray (trail.colora.location); qfeglEnableVertexAttribArray (prog.texoff.location);
qfeglEnableVertexAttribArray (trail.colorb.location); if (prog.colora.location >= 0)
qfeglEnableVertexAttribArray (prog.colora.location);
if (prog.colorb.location >= 0)
qfeglEnableVertexAttribArray (prog.colorb.location);
qfeglUniformMatrix4fv (trail.proj.location, 1, false, qfeglUniformMatrix4fv (prog.proj.location, 1, false,
(vec_t*)&glsl_projection[0]);//FIXME (vec_t*)&glsl_projection[0]);//FIXME
qfeglUniformMatrix4fv (trail.view.location, 1, false, qfeglUniformMatrix4fv (prog.view.location, 1, false,
(vec_t*)&glsl_view[0]);//FIXME (vec_t*)&glsl_view[0]);//FIXME
qfeglUniform2f (trail.viewport.location, r_refdef.vrect.width, qfeglUniform2f (prog.viewport.location, r_refdef.vrect.width,
r_refdef.vrect.height); r_refdef.vrect.height);
qfeglUniform1f (trail.width.location, 10); qfeglUniform1f (prog.width.location, 10);
qfeglVertexAttribPointer (trail.last.location, 4, GL_FLOAT, qfeglVertexAttribPointer (prog.last.location, 4, GL_FLOAT,
0, sizeof (trailvtx_t), &verts[0].vertex); 0, sizeof (trailvtx_t), &verts[0].vertex);
qfeglVertexAttribPointer (trail.current.location, 4, GL_FLOAT, qfeglVertexAttribPointer (prog.current.location, 4, GL_FLOAT,
0, sizeof (trailvtx_t), &verts[2].vertex); 0, sizeof (trailvtx_t), &verts[2].vertex);
qfeglVertexAttribPointer (trail.next.location, 4, GL_FLOAT, qfeglVertexAttribPointer (prog.next.location, 4, GL_FLOAT,
0, sizeof (trailvtx_t), &verts[4].vertex); 0, sizeof (trailvtx_t), &verts[4].vertex);
if (trail.barycentric.location >= 0) if (prog.barycentric.location >= 0)
qfeglVertexAttribPointer (trail.barycentric.location, 3, GL_FLOAT, qfeglVertexAttribPointer (prog.barycentric.location, 3, GL_FLOAT,
0, sizeof (trailvtx_t), &verts[2].bary); 0, sizeof (trailvtx_t), &verts[2].bary);
qfeglVertexAttribPointer (trail.texoff.location, 1, GL_FLOAT, qfeglVertexAttribPointer (prog.texoff.location, 1, GL_FLOAT,
0, sizeof (trailvtx_t), &verts[0].texoff); 0, sizeof (trailvtx_t), &verts[0].texoff);
qfeglVertexAttribPointer (trail.colora.location, 4, GL_FLOAT, if (prog.colora.location >= 0)
0, sizeof (trailvtx_t), &verts[0].colora); qfeglVertexAttribPointer (prog.colora.location, 4, GL_UNSIGNED_BYTE,
qfeglVertexAttribPointer (trail.colorb.location, 4, GL_FLOAT, 1, sizeof (trailvtx_t), &verts[0].colora);
0, sizeof (trailvtx_t), &verts[0].colorb); if (prog.colorb.location >= 0)
qfeglVertexAttribPointer (prog.colorb.location, 4, GL_UNSIGNED_BYTE,
1, sizeof (trailvtx_t), &verts[0].colorb);
for (first = 0, trl = trails_active; trl; trl = trl->next) { int first = 0;
int count; for (auto c = counts; *c; c++) {
if (trl->num_points < 2) qfeglDrawArrays (GL_TRIANGLE_STRIP, first, *c - 4);
continue; first += *c;
count = trl->num_points * 2;
qfeglDrawArrays (GL_TRIANGLE_STRIP, first, count);
first += count + 4;
} }
qfeglDisableVertexAttribArray (trail.last.location); qfeglDisableVertexAttribArray (prog.last.location);
qfeglDisableVertexAttribArray (trail.current.location); qfeglDisableVertexAttribArray (prog.current.location);
qfeglDisableVertexAttribArray (trail.next.location); qfeglDisableVertexAttribArray (prog.next.location);
if (trail.barycentric.location >= 0) if (prog.barycentric.location >= 0)
qfeglDisableVertexAttribArray (trail.barycentric.location); qfeglDisableVertexAttribArray (prog.barycentric.location);
qfeglDisableVertexAttribArray (trail.texoff.location); qfeglDisableVertexAttribArray (prog.texoff.location);
qfeglDisableVertexAttribArray (trail.colora.location); if (prog.colora.location >= 0)
qfeglDisableVertexAttribArray (trail.colorb.location); qfeglDisableVertexAttribArray (prog.colora.location);
if (prog.colorb.location >= 0)
expire_trails (); qfeglDisableVertexAttribArray (prog.colorb.location);
} }
static void __attribute__((used))//XXX void
glsl_R_DrawTrails (psystem_t *psystem) glsl_R_DrawTrails (psystem_t *psystem)
{ {
draw_trails (); //FIXME abuse of psystem_t
draw_trails ((trailpnt_t *)psystem->particles, psystem->numparticles);
} }
static psystem_t * __attribute__((const,used))//FIXME XXX psystem_t * __attribute__((const))//FIXME
glsl_TrailSystem (void) glsl_TrailSystem (void)
{ {
return &r_psystem; return &r_tsystem;
} }

View file

@ -614,4 +614,5 @@ R_Init_Cvars (void)
r_data->scr_viewsize = &scr_viewsize; r_data->scr_viewsize = &scr_viewsize;
R_Particles_Init_Cvars (); R_Particles_Init_Cvars ();
R_Trails_Init_Cvars ();
} }

View file

@ -105,4 +105,5 @@ R_Init (void)
r_funcs->R_Init (); r_funcs->R_Init ();
R_ClearEfrags (); //FIXME force link of r_efrag.o for qwaq R_ClearEfrags (); //FIXME force link of r_efrag.o for qwaq
Fog_Init (); Fog_Init ();
R_Trails_Init ();
} }

View file

@ -29,7 +29,6 @@
#endif #endif
#include "QF/cvar.h" #include "QF/cvar.h"
#include "QF/qargs.h"
#include "QF/render.h" #include "QF/render.h"
#include "QF/sys.h" #include "QF/sys.h"

View file

@ -190,6 +190,9 @@ render_scene (void)
EntQueue_Clear (r_ent_queue); EntQueue_Clear (r_ent_queue);
r_funcs->render_view (); r_funcs->render_view ();
r_funcs->draw_particles (&r_psystem); r_funcs->draw_particles (&r_psystem);
if (r_funcs->draw_trails) {
r_funcs->draw_trails (&r_tsystem);
}
r_funcs->draw_transparent (); r_funcs->draw_transparent ();
} }

View file

@ -0,0 +1,219 @@
/*
r_trails.c
Interface for trails
Copyright (C) 2023 Bill Currie <bill@taniwha.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "QF/cvar.h"
#include "QF/ecs.h"
#include "QF/render.h"
#include "QF/sys.h"
#include "QF/simd/vec4f.h"
#include "r_dynamic.h"
psystem_t r_tsystem; //FIXME singleton
static ecs_system_t trails_system;
static trailpnt_t *trail_point_buffer;
static uint32_t trail_point_count;
static uint32_t trail_point_buffer_size;
static uint32_t allocated_blocks; // bitmask of 64-point blocks in use
typedef struct {
uint32_t base;
uint32_t count;
} pointset_t;
enum trails_components {
trails_pointset,
trails_comp_count
};
static void
destroy_pointset (void *comp)
{
pointset_t *pointset = comp;
int base = pointset->base / 64;
int count = pointset->count / 64;
uint32_t mask = ((1 << count) - 1) << base;
allocated_blocks &= ~mask;
r_tsystem.numparticles = allocated_blocks;
}
static const component_t trails_components[trails_comp_count] = {
[trails_pointset] = {
.size = sizeof (pointset_t),
.create = 0,
.name = "pointset",
.destroy = destroy_pointset,
},
};
bool
R_Trail_Valid (psystem_t *system, uint32_t trailid)
{
return ECS_EntValid (trailid, trails_system.reg);
}
uint32_t
R_Trail_Create (psystem_t *system, int num_points, vec4f_t start)
{
num_points += 2; // need an extra point at either end
num_points = (num_points + 31) & ~31; // want a multiple of 32
num_points *= 2; // each point needs two verts
int blocks = num_points / 64;
uint32_t mask = (1 << blocks) - 1;
int block_ind;
for (block_ind = 0; block_ind <= 32 - blocks; block_ind++) {
if (!(allocated_blocks & mask)) {
break;
}
mask <<= 1;
}
if (allocated_blocks & mask) {
return nullent;
}
allocated_blocks |= mask;
r_tsystem.numparticles = allocated_blocks;
uint32_t trail = ECS_NewEntity (trails_system.reg);
pointset_t pointset = {
.base = block_ind * 64,
.count = num_points,
};
Ent_SetComponent (trail, trails_pointset, trails_system.reg, &pointset);
for (uint32_t i = 0; i < pointset.count; i++) {
static float bary[] = {0, 0, 1, 0, 0, 1, 0, 0};
auto p = trail_point_buffer + pointset.base + i;
*p = (trailpnt_t) {
.pos = start,
.colora = { 0xc0, 0xc0, 0xc0, 0xa0 },
.colorb = { 0x40, 0x40, 0x40, 0x40 },
.trailid = trail,
.live = 10,
};
p->pos[3] = i & 1 ? 1 : -1;
VectorCopy (bary + i % 3, p->bary);
};
return trail;
}
void
R_Trail_Update (psystem_t *system, uint32_t trailid, vec4f_t pos)
{
pointset_t *p = Ent_GetComponent (trailid, trails_pointset,
trails_system.reg);
trailpnt_t *points = trail_point_buffer + p->base;
pos[3] = -1;
vec4f_t dist = pos - points[4].pos;
vec4f_t prev1 = points[2].pos;
vec4f_t prev2 = points[3].pos;
points[2].pos = pos;
pos[3] = 1;
points[3].pos = pos;
points[0].pos = points[2].pos + dist;
points[1].pos = points[3].pos + dist;
if (dotf (dist, dist)[0] > 128) {
for (uint32_t i = 4; i < p->count; i += 2) {
vec4f_t t1 = points[i + 0].pos;
vec4f_t t2 = points[i + 1].pos;
points[i + 0].pos = prev1;
points[i + 1].pos = prev2;
prev1 = t1;
prev2 = t2;
}
}
}
void
R_Trail_Destroy (psystem_t *system, uint32_t trailid)
{
ECS_DelEntity (trails_system.reg, trailid);
}
void
R_ClearTrails (void)
{
auto reg = trails_system.reg;
for (uint32_t i = 0; i < reg->num_entities; i++) {
uint32_t ent = reg->entities[i];
uint32_t ind = Ent_Index (ent);
if (ind == i) {
ECS_DelEntity (reg, ent);
}
}
}
void
R_RunTrails (float dT)
{
}
void
R_Trails_Init_Cvars (void)
{
Sys_Printf ("R_Trails_Init_Cvars\n");
}
static void
trails_shutdown (void *data)
{
Sys_Printf ("trails_shutdown\n");
ECS_DelRegistry (trails_system.reg);
Sys_Free (trail_point_buffer, trail_point_buffer_size);
}
void
R_Trails_Init (void)
{
Sys_Printf ("R_Trails_Init\n");
Sys_RegisterShutdown (trails_shutdown, 0);
auto reg = ECS_NewRegistry ();
trails_system.reg = reg;
trails_system.base = ECS_RegisterComponents (reg, trails_components,
trails_comp_count);
ECS_CreateComponentPools (reg);
trail_point_count = 32*64;
trail_point_buffer_size = trail_point_count * sizeof (trailpnt_t);
trail_point_buffer = Sys_Alloc (trail_point_buffer_size);
r_tsystem = (psystem_t) {
.maxparticles = trail_point_count,
.particles = (particle_t *) trail_point_buffer,
.partparams = 0,//FIXME
.partramps = 0,//FIXME
};
}

View file

@ -477,6 +477,7 @@ vid_render_funcs_t glsl_vid_render_funcs = {
.Draw_Glyph = glsl_Draw_Glyph, .Draw_Glyph = glsl_Draw_Glyph,
.ParticleSystem = glsl_ParticleSystem, .ParticleSystem = glsl_ParticleSystem,
.TrailSystem = glsl_TrailSystem,
.R_Init = glsl_R_Init, .R_Init = glsl_R_Init,
.R_ClearState = glsl_R_ClearState, .R_ClearState = glsl_R_ClearState,
.R_LoadSkys = glsl_R_LoadSkys, .R_LoadSkys = glsl_R_LoadSkys,
@ -485,6 +486,7 @@ vid_render_funcs_t glsl_vid_render_funcs = {
.begin_frame = glsl_begin_frame, .begin_frame = glsl_begin_frame,
.render_view = glsl_render_view, .render_view = glsl_render_view,
.draw_particles = glsl_R_DrawParticles, .draw_particles = glsl_R_DrawParticles,
.draw_trails = glsl_R_DrawTrails,
.draw_transparent = glsl_draw_transparent, .draw_transparent = glsl_draw_transparent,
.post_process = glsl_post_process, .post_process = glsl_post_process,
.set_2d = glsl_set_2d, .set_2d = glsl_set_2d,

View file

@ -59,6 +59,7 @@
#include "compat.h" #include "compat.h"
#include "client/chase.h" #include "client/chase.h"
#include "client/effects.h"
#include "client/particles.h" #include "client/particles.h"
#include "client/sbar.h" #include "client/sbar.h"
#include "client/screen.h" #include "client/screen.h"
@ -737,6 +738,7 @@ CL_Init (cbuf_t *cbuf)
CL_Init_Input (cbuf); CL_Init_Input (cbuf);
CL_Particles_Init (); CL_Particles_Init ();
CL_Effects_Init ();
CL_TEnts_Init (); CL_TEnts_Init ();
CL_World_Init (); CL_World_Init ();
CL_ClearState (); CL_ClearState ();

View file

@ -98,6 +98,7 @@
#include "buildnum.h" #include "buildnum.h"
#include "compat.h" #include "compat.h"
#include "client/effects.h"
#include "client/particles.h" #include "client/particles.h"
#include "client/sbar.h" #include "client/sbar.h"
#include "client/screen.h" #include "client/screen.h"
@ -1488,6 +1489,7 @@ CL_Init (void)
CL_Init_Input (cl_cbuf); CL_Init_Input (cl_cbuf);
CL_Ents_Init (); CL_Ents_Init ();
CL_Particles_Init (); CL_Particles_Init ();
CL_Effects_Init ();
CL_TEnts_Init (); CL_TEnts_Init ();
CL_World_Init (); CL_World_Init ();
CL_ClearState (); CL_ClearState ();