quakeforge/libs/video/renderer/glsl/glsl_trails.c
Bill Currie 34daf9032d [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.
2023-11-23 13:58:44 +09:00

333 lines
8.8 KiB
C

/*
glsl_trails.c
OpenGL trail system.
Copyright (C) 2013 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
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#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 const char *particle_trail_debug_frag_effects[] =
{
"QuakeForge.Fragment.barycentric",
0
};
typedef 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;
} trailprog_t;
static trailprog_t 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},
};
static trailprog_t trail_debug;
typedef struct trailvtx_s {
vec4f_t vertex;
vec3_t bary;
float texoff;
byte colora[4];
byte colorb[4];
} trailvtx_t;
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_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_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);
vert = GLSL_CompileShader ("trail.vert", vert_shader, GL_VERTEX_SHADER);
frag = GLSL_CompileShader ("trail.frag", frag_shader, GL_FRAGMENT_SHADER);
debug = GLSL_CompileShader ("trail.frag.debug", debug_shader,
GL_FRAGMENT_SHADER);
trail_debug = trail;
build_program (&trail, "trail", vert, frag);
build_program (&trail_debug, "trail.debug", vert, debug);
GLSL_FreeShader (vert_shader);
GLSL_FreeShader (frag_shader);
GLSL_FreeShader (debug_shader);
alloc_arrays (&r_psystem);
}
static int
count_bits (uint32_t v)
{
int c = 0;
for (; v; c++) {
v &= v - 1;
}
return c;
}
static int
count_points (uint32_t block_mask)
{
int num_blocks = count_bits (block_mask);
return num_blocks * 64;
}
static void
build_verts (trailvtx_t *verts, int *counts,
const trailpnt_t *points, uint32_t block_mask)
{
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)},
};
}
verts += 64;
}
}
static void
draw_trails (trailpnt_t *points, uint32_t block_mask)
{
int num_verts = count_points (block_mask);
if (!num_verts) {
return;
}
trailvtx_t verts[num_verts];
int counts[33] = {};
build_verts (verts, counts, points, block_mask);
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);
}
void
glsl_R_DrawTrails (psystem_t *psystem)
{
//FIXME abuse of psystem_t
draw_trails ((trailpnt_t *)psystem->particles, psystem->numparticles);
}
psystem_t * __attribute__((const))//FIXME
glsl_TrailSystem (void)
{
return &r_tsystem;
}