diff --git a/include/QF/GLSL/qf_particles.h b/include/QF/GLSL/qf_particles.h index a6a4111f8..1c6a2108d 100644 --- a/include/QF/GLSL/qf_particles.h +++ b/include/QF/GLSL/qf_particles.h @@ -44,4 +44,8 @@ void glsl_R_Particles_Init_Cvars (void); void glsl_R_InitParticles (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 diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 50a7443a8..c1e802273 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -118,6 +118,7 @@ typedef struct vid_render_funcs_s { void (*Draw_Glyph) (int x, int y, int fontid, int glyphid, int c); struct psystem_s *(*ParticleSystem) (void); + struct psystem_s *(*TrailSystem) (void); void (*R_Init) (void); void (*R_ClearState) (void); void (*R_LoadSkys) (const char *); @@ -127,6 +128,7 @@ typedef struct vid_render_funcs_s { void (*begin_frame) (void); void (*render_view) (void); void (*draw_particles) (struct psystem_s *psystem); + void (*draw_trails) (struct psystem_s *psystem); void (*draw_transparent) (void); void (*post_process) (struct framebuffer_s *src); void (*set_2d) (int scaled); diff --git a/include/QF/render.h b/include/QF/render.h index 51950eeb4..cd522ab0f 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -41,10 +41,8 @@ typedef enum { part_tex_smoke, } ptextype_t; -typedef struct particle_s particle_t; - // !!! 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 vel; @@ -61,7 +59,24 @@ struct particle_s { float ramp; float scale; 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 { vec4f_t drag; // drag[3] is grav scale @@ -71,6 +86,9 @@ typedef struct partparm_s { float alpha_rate; } partparm_t; +static_assert (sizeof (partparm_t) == 2 * sizeof(vec4f_t), + "partparm_t wrong size"); + typedef struct psystem_s { vec4f_t gravity; uint32_t maxparticles; @@ -186,4 +204,9 @@ void Fog_StartAdditive (void); void Fog_StopAdditive (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 diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index 651878036..8d279d7ab 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -75,7 +75,7 @@ typedef struct visibility_s { typedef struct renderer_s { struct model_s *model; // NULL = no model struct skin_s *skin; - struct trail_s *trail; // FIXME should be own component + struct trail_s *trail; unsigned fullbright:1; unsigned noshadows:1; unsigned onlyshadows:1; diff --git a/include/client/effects.h b/include/client/effects.h index 16214742a..e152bce32 100644 --- a/include/client/effects.h +++ b/include/client/effects.h @@ -36,6 +36,7 @@ enum { effect_light, // light entity id effect_muzzleflash, // light entity id + effect_trail, // trail id effect_comp_count, }; @@ -54,5 +55,6 @@ void CL_EntityEffects (struct entity_s ent, struct entity_state_s *state, double time); void CL_MuzzleFlash (struct entity_s ent, vec4f_t position, vec4f_t fv, float zoffset, double time); +void CL_Effects_Init (void); #endif//__client_effects_h diff --git a/include/r_dynamic.h b/include/r_dynamic.h index 454e8d454..6690fc8ad 100644 --- a/include/r_dynamic.h +++ b/include/r_dynamic.h @@ -45,16 +45,13 @@ typedef enum { struct entity_s; -void R_Particles_Init_Cvars (void); -void R_Particle_New (const char *type, int texnum, const vec3_t org, - float scale, const vec3_t vel, float die, int color, - float alpha, float ramp); -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_Trails_Init (void); +void R_Trails_Init_Cvars (void); +void R_ClearTrails (void); +void R_RunTrails (float dT); -void R_InitParticles (void); +void R_RunParticles (float dT); +void R_Particles_Init_Cvars (void); void R_ClearParticles (void); void R_InitSprites (void); diff --git a/include/r_internal.h b/include/r_internal.h index 0436d126d..b37ae3918 100644 --- a/include/r_internal.h +++ b/include/r_internal.h @@ -42,10 +42,11 @@ void R_ViewChanged (void); // must set r_refdef first // called whenever r_refdef or vid change extern struct psystem_s r_psystem; +extern struct psystem_s r_tsystem; struct psystem_s *gl_ParticleSystem (void); struct psystem_s *glsl_ParticleSystem (void); +struct psystem_s *glsl_TrailSystem (void); struct psystem_s *sw_ParticleSystem (void); -void R_RunParticles (float dT); struct scene_s; void R_NewScene (struct scene_s *scene); diff --git a/libs/client/cl_effects.c b/libs/client/cl_effects.c index 04863e93d..b34fad885 100644 --- a/libs/client/cl_effects.c +++ b/libs/client/cl_effects.c @@ -53,6 +53,15 @@ 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] = { [effect_light] = { .size = sizeof (uint32_t), @@ -62,9 +71,15 @@ const component_t effect_components[effect_comp_count] = { .size = sizeof (uint32_t), .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_trail (effect_system.base + effect_trail) static bool has_light (entity_t ent) @@ -98,6 +113,27 @@ attach_light_ent (entity_t ent) 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 CL_NewDlight (entity_t ent, vec4f_t org, int effects, byte glow_size, 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); 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; } else if (model->effects & ME_GRENADE) 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); } } + +void +CL_Effects_Init (void) +{ + if (r_funcs->TrailSystem) { + cl_tsystem = r_funcs->TrailSystem (); + } +} diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index 2036b7a36..3cf3a388b 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -58,9 +58,10 @@ libs_video_renderer_libQFrenderer_la_SOURCES=\ libs/video/renderer/r_light.c \ libs/video/renderer/r_main.c \ libs/video/renderer/r_part.c \ + libs/video/renderer/r_progs.c \ libs/video/renderer/r_scrap.c \ libs/video/renderer/r_screen.c \ - libs/video/renderer/r_progs.c + libs/video/renderer/r_trails.c video_renderer_gl_libs= \ libs/video/renderer/librender_gl.la \ diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index 06601e743..2c8febac4 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -186,6 +186,7 @@ glsl_R_Init (void) glsl_R_InitIQM (); glsl_R_InitSprites (); glsl_R_InitParticles (); + glsl_R_InitTrails (); glsl_InitFisheye (); glsl_InitWarp (); Skin_Init (); diff --git a/libs/video/renderer/glsl/glsl_trails.c b/libs/video/renderer/glsl/glsl_trails.c index 282a078fa..a44d22cf4 100644 --- a/libs/video/renderer/glsl/glsl_trails.c +++ b/libs/video/renderer/glsl/glsl_trails.c @@ -87,9 +87,8 @@ static const char *particle_trail_debug_frag_effects[] = 0 }; -static struct { +typedef struct { int program; - int debug_program; shaderparam_t proj; shaderparam_t view; shaderparam_t viewport; @@ -101,8 +100,10 @@ static struct { shaderparam_t texoff; shaderparam_t colora; shaderparam_t colorb; -} trail = { - 0, 0, +} trailprog_t; + +static trailprog_t trail = { + 0, {"projection_mat", 1}, {"view_mat", 1}, {"viewport", 1}, @@ -115,62 +116,16 @@ static struct { {"vcolora", 0}, {"vcolorb", 0}, }; - -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; +static trailprog_t trail_debug; typedef struct trailvtx_s { - quat_t vertex; + vec4f_t vertex; vec3_t bary; float texoff; - quat_t colora; - quat_t colorb; + byte colora[4]; + byte colorb[4]; } 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 alloc_arrays (psystem_t *ps) { @@ -197,20 +152,38 @@ alloc_arrays (psystem_t *ps) } void -glsl_R_ShutdownParticles (void) +glsl_R_ShutdownTrails (void) { free (particleVertexArray); 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 -glsl_R_InitParticles (void) +glsl_R_InitTrails (void) { shader_t *vert_shader, *frag_shader, *debug_shader; int vert; int frag; int debug; + vert_shader = GLSL_BuildShader (particle_trail_vert_effects); frag_shader = GLSL_BuildShader (particle_trail_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); debug = GLSL_CompileShader ("trail.frag.debug", debug_shader, GL_FRAGMENT_SHADER); - trail.program = GLSL_LinkProgram ("trail", vert, frag); - trail.debug_program = GLSL_LinkProgram ("trail.debug", vert, debug); + trail_debug = trail; + 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 (frag_shader); + GLSL_FreeShader (debug_shader); alloc_arrays (&r_psystem); } -static void -add_trail_to_ent (entity_t ent) +static int +count_bits (uint32_t v) { - renderer_t *r = Ent_GetComponent (ent.id, scene_renderer, ent.reg); - r->trail = new_trail (); - r->trail->next = trails_active; - r->trail->prev = &trails_active; - r->trail->owner = &r->trail; - 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 (); - *point = (point_t) { - .p.pos = origin, - .p.color = (vec4f_t) {1,1,1,1},//ramp3[ramp = mtwist_rand (&mt) & 3],XXX - .p.tex = part_tex_smoke, - .p.scale = pscale + percent * 4.0, - .p.alpha = 0.5 + qfrandom (0.125) - percent * 0.40, - .p.vel = {}, - .p.live = 2.0 - percent * 2.0, - // .p.ramp = ramp,XXX - // .p.physics = R_ParticlePhysics ("pt_float"),XXX pt_static for debug - }; - - return point; -} - -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; + int c = 0; + for (; v; c++) { + v &= v - 1; } + return c; } -static inline void -set_vertex (trailvtx_t *v, const point_t *point, float w, const vec3_t bary, - float off) + +static int +count_points (uint32_t block_mask) { - 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); + int num_blocks = count_bits (block_mask); + return num_blocks * 64; } static void -count_points (int *num_verts) +build_verts (trailvtx_t *verts, int *counts, + const trailpnt_t *points, uint32_t block_mask) { - trail_t *trail; - - *num_verts = 0; - for (trail = trails_active; trail; trail = trail->next) { - if (trail->num_points < 2) + uint32_t id = ~0u; + for (int m = 0; m < 32; m++, points += 64) { + if (!(block_mask & (1 << m))) { + if (*counts) { + counts++; + } 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; + } + 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)}, + }; + } + verts += 64; } } static void -build_verts (trailvtx_t *v) +draw_trails (trailpnt_t *points, uint32_t block_mask) { - trail_t *trail; - point_t *point, *last_point = 0, *second_last_point = 0; - 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) + int num_verts = count_points (block_mask); + if (!num_verts) { return; - - verts = alloca (num_verts * sizeof (trailvtx_t)); - build_verts (verts); - - qfeglUseProgram (trail.program); - qfeglEnableVertexAttribArray (trail.last.location); - qfeglEnableVertexAttribArray (trail.current.location); - qfeglEnableVertexAttribArray (trail.next.location); - if (trail.barycentric.location >= 0) - qfeglEnableVertexAttribArray (trail.barycentric.location); - qfeglEnableVertexAttribArray (trail.texoff.location); - qfeglEnableVertexAttribArray (trail.colora.location); - qfeglEnableVertexAttribArray (trail.colorb.location); - - qfeglUniformMatrix4fv (trail.proj.location, 1, false, - (vec_t*)&glsl_projection[0]);//FIXME - qfeglUniformMatrix4fv (trail.view.location, 1, false, - (vec_t*)&glsl_view[0]);//FIXME - qfeglUniform2f (trail.viewport.location, r_refdef.vrect.width, - r_refdef.vrect.height); - qfeglUniform1f (trail.width.location, 10); - - qfeglVertexAttribPointer (trail.last.location, 4, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[0].vertex); - qfeglVertexAttribPointer (trail.current.location, 4, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[2].vertex); - qfeglVertexAttribPointer (trail.next.location, 4, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[4].vertex); - if (trail.barycentric.location >= 0) - qfeglVertexAttribPointer (trail.barycentric.location, 3, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[2].bary); - qfeglVertexAttribPointer (trail.texoff.location, 1, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[0].texoff); - qfeglVertexAttribPointer (trail.colora.location, 4, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[0].colora); - qfeglVertexAttribPointer (trail.colorb.location, 4, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[0].colorb); - - for (first = 0, trl = trails_active; trl; trl = trl->next) { - int count; - if (trl->num_points < 2) - continue; - count = trl->num_points * 2; - qfeglDrawArrays (GL_TRIANGLE_STRIP, first, count); - first += count + 4; } - qfeglDisableVertexAttribArray (trail.last.location); - qfeglDisableVertexAttribArray (trail.current.location); - qfeglDisableVertexAttribArray (trail.next.location); - if (trail.barycentric.location >= 0) - qfeglDisableVertexAttribArray (trail.barycentric.location); - qfeglDisableVertexAttribArray (trail.texoff.location); - qfeglDisableVertexAttribArray (trail.colora.location); - qfeglDisableVertexAttribArray (trail.colorb.location); + trailvtx_t verts[num_verts]; + int counts[33] = {}; + build_verts (verts, counts, points, block_mask); - expire_trails (); + auto prog = trail; + qfeglUseProgram (prog.program); + qfeglEnableVertexAttribArray (prog.last.location); + qfeglEnableVertexAttribArray (prog.current.location); + qfeglEnableVertexAttribArray (prog.next.location); + if (prog.barycentric.location >= 0) + qfeglEnableVertexAttribArray (prog.barycentric.location); + qfeglEnableVertexAttribArray (prog.texoff.location); + if (prog.colora.location >= 0) + qfeglEnableVertexAttribArray (prog.colora.location); + if (prog.colorb.location >= 0) + qfeglEnableVertexAttribArray (prog.colorb.location); + + qfeglUniformMatrix4fv (prog.proj.location, 1, false, + (vec_t*)&glsl_projection[0]);//FIXME + qfeglUniformMatrix4fv (prog.view.location, 1, false, + (vec_t*)&glsl_view[0]);//FIXME + qfeglUniform2f (prog.viewport.location, r_refdef.vrect.width, + r_refdef.vrect.height); + qfeglUniform1f (prog.width.location, 10); + + qfeglVertexAttribPointer (prog.last.location, 4, GL_FLOAT, + 0, sizeof (trailvtx_t), &verts[0].vertex); + qfeglVertexAttribPointer (prog.current.location, 4, GL_FLOAT, + 0, sizeof (trailvtx_t), &verts[2].vertex); + qfeglVertexAttribPointer (prog.next.location, 4, GL_FLOAT, + 0, sizeof (trailvtx_t), &verts[4].vertex); + if (prog.barycentric.location >= 0) + qfeglVertexAttribPointer (prog.barycentric.location, 3, GL_FLOAT, + 0, sizeof (trailvtx_t), &verts[2].bary); + qfeglVertexAttribPointer (prog.texoff.location, 1, GL_FLOAT, + 0, sizeof (trailvtx_t), &verts[0].texoff); + if (prog.colora.location >= 0) + qfeglVertexAttribPointer (prog.colora.location, 4, GL_UNSIGNED_BYTE, + 1, sizeof (trailvtx_t), &verts[0].colora); + if (prog.colorb.location >= 0) + qfeglVertexAttribPointer (prog.colorb.location, 4, GL_UNSIGNED_BYTE, + 1, sizeof (trailvtx_t), &verts[0].colorb); + + int first = 0; + for (auto c = counts; *c; c++) { + qfeglDrawArrays (GL_TRIANGLE_STRIP, first, *c - 4); + first += *c; + } + + qfeglDisableVertexAttribArray (prog.last.location); + qfeglDisableVertexAttribArray (prog.current.location); + qfeglDisableVertexAttribArray (prog.next.location); + if (prog.barycentric.location >= 0) + qfeglDisableVertexAttribArray (prog.barycentric.location); + qfeglDisableVertexAttribArray (prog.texoff.location); + if (prog.colora.location >= 0) + qfeglDisableVertexAttribArray (prog.colora.location); + if (prog.colorb.location >= 0) + qfeglDisableVertexAttribArray (prog.colorb.location); } -static void __attribute__((used))//XXX +void 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) { - return &r_psystem; + return &r_tsystem; } diff --git a/libs/video/renderer/r_cvar.c b/libs/video/renderer/r_cvar.c index df3d44bbc..aa88d6270 100644 --- a/libs/video/renderer/r_cvar.c +++ b/libs/video/renderer/r_cvar.c @@ -614,4 +614,5 @@ R_Init_Cvars (void) r_data->scr_viewsize = &scr_viewsize; R_Particles_Init_Cvars (); + R_Trails_Init_Cvars (); } diff --git a/libs/video/renderer/r_init.c b/libs/video/renderer/r_init.c index d4279fda0..0f0915e4c 100644 --- a/libs/video/renderer/r_init.c +++ b/libs/video/renderer/r_init.c @@ -105,4 +105,5 @@ R_Init (void) r_funcs->R_Init (); R_ClearEfrags (); //FIXME force link of r_efrag.o for qwaq Fog_Init (); + R_Trails_Init (); } diff --git a/libs/video/renderer/r_part.c b/libs/video/renderer/r_part.c index 4227dd6ec..b97fff906 100644 --- a/libs/video/renderer/r_part.c +++ b/libs/video/renderer/r_part.c @@ -29,7 +29,6 @@ #endif #include "QF/cvar.h" -#include "QF/qargs.h" #include "QF/render.h" #include "QF/sys.h" diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 4f71d5212..efd51176b 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -190,6 +190,9 @@ render_scene (void) EntQueue_Clear (r_ent_queue); r_funcs->render_view (); r_funcs->draw_particles (&r_psystem); + if (r_funcs->draw_trails) { + r_funcs->draw_trails (&r_tsystem); + } r_funcs->draw_transparent (); } diff --git a/libs/video/renderer/r_trails.c b/libs/video/renderer/r_trails.c new file mode 100644 index 000000000..9d7255e76 --- /dev/null +++ b/libs/video/renderer/r_trails.c @@ -0,0 +1,219 @@ +/* + r_trails.c + + Interface for trails + + Copyright (C) 2023 Bill Currie + + 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 + }; +} diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index 38318ab1d..c164982ec 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -477,6 +477,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { .Draw_Glyph = glsl_Draw_Glyph, .ParticleSystem = glsl_ParticleSystem, + .TrailSystem = glsl_TrailSystem, .R_Init = glsl_R_Init, .R_ClearState = glsl_R_ClearState, .R_LoadSkys = glsl_R_LoadSkys, @@ -485,6 +486,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { .begin_frame = glsl_begin_frame, .render_view = glsl_render_view, .draw_particles = glsl_R_DrawParticles, + .draw_trails = glsl_R_DrawTrails, .draw_transparent = glsl_draw_transparent, .post_process = glsl_post_process, .set_2d = glsl_set_2d, diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index f8f21c98b..bb5d6b7b8 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -59,6 +59,7 @@ #include "compat.h" #include "client/chase.h" +#include "client/effects.h" #include "client/particles.h" #include "client/sbar.h" #include "client/screen.h" @@ -737,6 +738,7 @@ CL_Init (cbuf_t *cbuf) CL_Init_Input (cbuf); CL_Particles_Init (); + CL_Effects_Init (); CL_TEnts_Init (); CL_World_Init (); CL_ClearState (); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 5f6287a82..16b6f45cc 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -98,6 +98,7 @@ #include "buildnum.h" #include "compat.h" +#include "client/effects.h" #include "client/particles.h" #include "client/sbar.h" #include "client/screen.h" @@ -1488,6 +1489,7 @@ CL_Init (void) CL_Init_Input (cl_cbuf); CL_Ents_Init (); CL_Particles_Init (); + CL_Effects_Init (); CL_TEnts_Init (); CL_World_Init (); CL_ClearState ();