diff --git a/include/QF/scene/entity.h b/include/QF/scene/entity.h index a59496759..651878036 100644 --- a/include/QF/scene/entity.h +++ b/include/QF/scene/entity.h @@ -75,6 +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 unsigned fullbright:1; unsigned noshadows:1; unsigned onlyshadows:1; diff --git a/libs/video/renderer/Makemodule.am b/libs/video/renderer/Makemodule.am index d0015579b..2036b7a36 100644 --- a/libs/video/renderer/Makemodule.am +++ b/libs/video/renderer/Makemodule.am @@ -135,6 +135,7 @@ libs_video_renderer_librender_glsl_la_SOURCES = \ libs/video/renderer/glsl/glsl_shader.c \ libs/video/renderer/glsl/glsl_sprite.c \ libs/video/renderer/glsl/glsl_textures.c \ + libs/video/renderer/glsl/glsl_trails.c \ libs/video/renderer/glsl/glsl_warp.c \ libs/video/renderer/glsl/qfglsl.c \ libs/video/renderer/glsl/quakeforge.glsl \ diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index f86d7afb6..9f8407765 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -98,24 +98,6 @@ static const char *particle_textured_frag_effects[] = 0 }; -static const char *particle_trail_vert_effects[] = -{ - "QuakeForge.Screen.viewport", - "QuakeForge.Vertex.transform.view_projection", - "QuakeForge.Vertex.ScreenSpace.curve.width", - "QuakeForge.Vertex.particle.trail", - 0 -}; - -static const char *particle_trail_frag_effects[] = -{ - "QuakeForge.Math.InvSqrt", - "QuakeForge.Math.permute", - "QuakeForge.Noise.simplex", - "QuakeForge.Fragment.particle.trail", - 0 -}; - static struct { int program; shaderparam_t mvp_matrix; @@ -150,84 +132,6 @@ static struct { {"fog", 1}, }; -static struct { - int program; - shaderparam_t proj; - shaderparam_t view; - shaderparam_t viewport; - shaderparam_t width; - shaderparam_t last; - shaderparam_t current; - shaderparam_t next; - shaderparam_t barycentric; - shaderparam_t texoff; - shaderparam_t colora; - shaderparam_t colorb; -} trail = { - 0, - {"projection_mat", 1}, - {"view_mat", 1}, - {"viewport", 1}, - {"width", 1}, - {"last", 0}, - {"current", 0}, - {"next", 0}, - {"barycentric", 0}, - {"texoff", 0}, - {"vcolora", 0}, - {"vcolorb", 0}, -}; -#if 0 -typedef struct trail_s { - struct trail_s *next; - struct trail_s **prev; - struct trail_s **owner; - particle_t *points; - particle_t **head; // new points are appended to the list - int num_points; -} trail_t; - -typedef struct trailvtx_s { - quat_t vertex; - vec3_t bary; - float texoff; - quat_t colora; - quat_t colorb; -} trailvtx_t; - -ALLOC_STATE (trail_t, trails); -ALLOC_STATE (particle_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 particle_t * -new_point (void) -{ - particle_t *point; - ALLOC (128, particle_t, points, point); - return point; -} - -static void -free_point (particle_t *point) -{ - FREE (points, point); -} -#endif static void alloc_arrays (psystem_t *ps) { @@ -316,25 +220,6 @@ glsl_R_InitParticles (void) GLSL_FreeShader (vert_shader); GLSL_FreeShader (frag_shader); - vert_shader = GLSL_BuildShader (particle_trail_vert_effects); - frag_shader = GLSL_BuildShader (particle_trail_frag_effects); - vert = GLSL_CompileShader ("trail.vert", vert_shader, GL_VERTEX_SHADER); - frag = GLSL_CompileShader ("trail.frag", frag_shader, GL_FRAGMENT_SHADER); - trail.program = GLSL_LinkProgram ("trail", vert, frag); - 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); - memset (data, 0, sizeof (data)); qfeglGenTextures (1, &part_tex); qfeglBindTexture (GL_TEXTURE_2D, part_tex); @@ -357,238 +242,7 @@ glsl_R_InitParticles (void) alloc_arrays (&r_psystem); } -#if 0 -static void -add_trail_to_ent (entity_t *ent) -{ - ent->trail = new_trail (); - ent->trail->next = trails_active; - ent->trail->prev = &trails_active; - ent->trail->owner = &ent->trail; - if (trails_active) - trails_active->prev = &ent->trail->next; - trails_active = ent->trail; -} -static inline particle_t * -new_trail_point (const vec3_t origin, float pscale, float percent) -{ - particle_t *point; - int ramp; - - point = new_point (); - VectorCopy (origin, point->org); - point->color = ramp3[ramp = mtwist_rand (&mt) & 3]; - point->tex = part_tex_smoke; - point->scale = pscale + percent * 4.0; - point->alpha = 0.5 + qfrandom (0.125) - percent * 0.40; - VectorCopy (vec3_origin, point->vel); - point->die = vr_data.realtime + 2.0 - percent * 2.0; - point->ramp = ramp; - point->physics = R_ParticlePhysics ("pt_float"); - - return point; -} - -static inline void -add_point_to_trail (trail_t *trail, particle_t *point) -{ - *trail->head = point; - trail->head = &point->next; - trail->num_points++; -} - -static void -R_RocketTrail_trail (entity_t *ent) -{ - float dist, maxlen, origlen, percent, pscale, pscalenext; - float len = 0.0; - vec3_t old_origin, vec; - particle_t *point; - - if (!ent->trail) { - add_trail_to_ent (ent); - } - - VectorCopy (ent->old_origin, old_origin); - VectorSubtract (ent->origin, old_origin, vec); - maxlen = VectorNormalize (vec); - origlen = vr_data.frametime / maxlen; - pscale = 1.5 + qfrandom (1.5); - - while (len < maxlen) { - pscalenext = 1.5 + qfrandom (1.5); - dist = (pscale + pscalenext) * 3.0; - percent = len * origlen; - - point = new_trail_point (old_origin, pscale, percent); - - add_point_to_trail (ent->trail, point); - - len += dist; - VectorMultAdd (old_origin, len, vec, old_origin); - pscale = pscalenext; - } -} - -static inline void -set_vertex (trailvtx_t *v, const particle_t *point, float w, const vec3_t bary, - float off) -{ - byte *color = (byte *) &d_8to24table[(byte) point->color]; - - VectorCopy (point->org, v->vertex); - VectorCopy (bary, v->bary); - v->vertex[3] = w * point->scale; - v->texoff = off; - VectorScale (color, 1.5 / 255, v->colora); - v->colora[3] = point->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 (even though the distance between points will - // be 0), thus need vertices for two extra points. - *num_verts += (trail->num_points + 2) * 2; - } -} - -static void -build_verts (trailvtx_t *v) -{ - trail_t *trail; - particle_t *point, *last_point = 0, *second_last_point = 0; - particle_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; - VectorScale (point->org, 2, dup.org); - VectorSubtract (dup.org, point->next->org, dup.org); - 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); - } - VectorScale (last_point->org, 2, dup.org); - VectorSubtract (dup.org, second_last_point->org, dup.org); - 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->die <= vr_data.realtime) { - particle_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; - - 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, glsl_projection); - qfeglUniformMatrix4fv (trail.view.location, 1, false, glsl_view); - 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); - - expire_trails (); -} -#endif static void draw_qf_particles (psystem_t *psystem) { @@ -780,9 +434,6 @@ draw_id_particles (psystem_t *psystem) void glsl_R_DrawParticles (psystem_t *psystem) { -#if 0 - draw_trails (); -#endif if (!psystem->numparticles) { return; } diff --git a/libs/video/renderer/glsl/glsl_trails.c b/libs/video/renderer/glsl/glsl_trails.c new file mode 100644 index 000000000..a3abeb34c --- /dev/null +++ b/libs/video/renderer/glsl/glsl_trails.c @@ -0,0 +1,474 @@ +/* + glsl_trails.c + + OpenGL trail system. + + Copyright (C) 2013 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 + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/alloc.h" +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/image.h" +#include "QF/mersenne.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" +#include "QF/render.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "QF/scene/entity.h" + +#include "QF/GLSL/defines.h" +#include "QF/GLSL/funcs.h" +#include "QF/GLSL/qf_particles.h" +#include "QF/GLSL/qf_textures.h" +#include "QF/GLSL/qf_vid.h" + +#include "r_internal.h" +#include "r_local.h" + +static uint32_t maxparticles; +static GLushort *pVAindices; +static partvert_t *particleVertexArray; + +static const char *particle_trail_vert_effects[] = +{ + "QuakeForge.Screen.viewport", + "QuakeForge.Vertex.transform.view_projection", + "QuakeForge.Vertex.ScreenSpace.curve.width", + "QuakeForge.Vertex.particle.trail", + 0 +}; + +static const char *particle_trail_frag_effects[] = +{ + "QuakeForge.Math.InvSqrt", + "QuakeForge.Math.permute", + "QuakeForge.Noise.simplex", + "QuakeForge.Fragment.particle.trail", + 0 +}; + +static struct { + int program; + shaderparam_t proj; + shaderparam_t view; + shaderparam_t viewport; + shaderparam_t width; + shaderparam_t last; + shaderparam_t current; + shaderparam_t next; + shaderparam_t barycentric; + shaderparam_t texoff; + shaderparam_t colora; + shaderparam_t colorb; +} trail = { + 0, + {"projection_mat", 1}, + {"view_mat", 1}, + {"viewport", 1}, + {"width", 1}, + {"last", 0}, + {"current", 0}, + {"next", 0}, + {"barycentric", 0}, + {"texoff", 0}, + {"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; + +typedef struct trailvtx_s { + quat_t vertex; + vec3_t bary; + float texoff; + quat_t colora; + quat_t colorb; +} 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) +{ + if (ps->maxparticles > maxparticles) { + maxparticles = ps->maxparticles; + if (particleVertexArray) + free (particleVertexArray); + printf ("alloc_arrays: %d\n", ps->maxparticles); + particleVertexArray = calloc (ps->maxparticles * 4, + sizeof (partvert_t)); + + if (pVAindices) + free (pVAindices); + pVAindices = calloc (ps->maxparticles * 6, sizeof (GLushort)); + for (uint32_t i = 0; i < ps->maxparticles; i++) { + pVAindices[i * 6 + 0] = i * 4 + 0; + pVAindices[i * 6 + 1] = i * 4 + 1; + pVAindices[i * 6 + 2] = i * 4 + 2; + pVAindices[i * 6 + 3] = i * 4 + 0; + pVAindices[i * 6 + 4] = i * 4 + 2; + pVAindices[i * 6 + 5] = i * 4 + 3; + } + } +} + +void +glsl_R_ShutdownParticles (void) +{ + free (particleVertexArray); + free (pVAindices); +} + +void +glsl_R_InitParticles (void) +{ + shader_t *vert_shader, *frag_shader; + int vert; + int frag; + + vert_shader = GLSL_BuildShader (particle_trail_vert_effects); + frag_shader = GLSL_BuildShader (particle_trail_frag_effects); + vert = GLSL_CompileShader ("trail.vert", vert_shader, GL_VERTEX_SHADER); + frag = GLSL_CompileShader ("trail.frag", frag_shader, GL_FRAGMENT_SHADER); + trail.program = GLSL_LinkProgram ("trail", vert, frag); + 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); + + alloc_arrays (&r_psystem); +} + +static void +add_trail_to_ent (entity_t ent) +{ + 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 + }; + + 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; + } +} + +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; + 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 +build_verts (trailvtx_t *v) +{ + 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) + 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); + + expire_trails (); +} + +static void __attribute__((used))//XXX +glsl_R_DrawTrails (psystem_t *psystem) +{ + draw_trails (); +} + +static psystem_t * __attribute__((const,used))//FIXME XXX +glsl_TrailSystem (void) +{ + return &r_psystem; +}