From ddd8885cd65ce0a1c041d5373ea8959a823995d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Feb 2013 11:40:11 +0900 Subject: [PATCH 01/31] Start working on solid trails for smoke etc. The implementation is based on http://codeflow.org/entries/2012/aug/05/webgl-rendering-of-solid-trails/ The shaders have been written and compile and link. The next step is to generate some data for them. --- libs/video/renderer/glsl/Makefile.am | 4 +- libs/video/renderer/glsl/glsl_particles.c | 48 ++++++++++++++++ libs/video/renderer/glsl/trail.frag | 10 ++++ libs/video/renderer/glsl/trail.vert | 68 +++++++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 libs/video/renderer/glsl/trail.frag create mode 100644 libs/video/renderer/glsl/trail.vert diff --git a/libs/video/renderer/glsl/Makefile.am b/libs/video/renderer/glsl/Makefile.am index ca8f4314a..4072d5ac0 100644 --- a/libs/video/renderer/glsl/Makefile.am +++ b/libs/video/renderer/glsl/Makefile.am @@ -3,8 +3,8 @@ AUTOMAKE_OPTIONS= foreign AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include $(GLX_CFLAGS) -shader_src= quakeforge.glsl -shader_gen= quakeforge.slc +shader_src= quakeforge.glsl trail.frag trail.vert +shader_gen= quakeforge.slc trail.fc trail.vc glsl_src = \ glsl_alias.c glsl_bsp.c glsl_draw.c glsl_fog.c glsl_iqm.c glsl_lightmap.c \ diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index c4e214c50..f1aa9f79b 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -106,6 +106,14 @@ static const char *particle_textured_frag_effects[] = 0 }; +static const char trail_vert[] = +#include "trail.vc" +; + +static const char trail_frag[] = +#include "trail.fc" +; + static struct { int program; shaderparam_t mvp_matrix; @@ -140,6 +148,32 @@ 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 smoke; +} trail = { + 0, + {"proj", 1}, + {"view", 1}, + {"viewport", 1}, + {"width", 1}, + {"last", 0}, + {"current", 0}, + {"next", 0}, + {"barycentric", 0}, + {"texoff", 0}, + {"smoke", 1}, +}; + inline static void particle_new (ptype_t type, int texnum, const vec3_t org, float scale, const vec3_t vel, float die, int color, float alpha, float ramp) @@ -267,6 +301,20 @@ glsl_R_InitParticles (void) GLSL_FreeShader (vert_shader); GLSL_FreeShader (frag_shader); + vert = GLSL_CompileShader ("trail.vert", trail_vert, GL_VERTEX_SHADER); + frag = GLSL_CompileShader ("trail.frag", trail_frag, 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.smoke); + memset (data, 0, sizeof (data)); qfeglGenTextures (1, &part_tex); qfeglBindTexture (GL_TEXTURE_2D, part_tex); diff --git a/libs/video/renderer/glsl/trail.frag b/libs/video/renderer/glsl/trail.frag new file mode 100644 index 000000000..2dd3f2b31 --- /dev/null +++ b/libs/video/renderer/glsl/trail.frag @@ -0,0 +1,10 @@ +uniform sampler2D smoke; + +varying vec2 texcoord; +varying vec3 vBC; + +void +main (void) +{ + gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); +} diff --git a/libs/video/renderer/glsl/trail.vert b/libs/video/renderer/glsl/trail.vert new file mode 100644 index 000000000..f942db8c2 --- /dev/null +++ b/libs/video/renderer/glsl/trail.vert @@ -0,0 +1,68 @@ +attribute vec4 last, current, next; +attribute vec3 barycentric; +attribute float texoff; + +uniform mat4 proj, view; +uniform vec2 viewport; +uniform float width; + +varying vec2 texcoord; +varying vec3 vBC; + +vec4 +transform (vec3 coord) +{ + return proj * view * vec4 (coord, 1.0); +} + +vec2 +project (vec4 coord) +{ + vec3 device = coord.xyz / coord.w; + vec2 clip = (device * 0.5 + 0.5).xy; + return clip * viewport; +} + +vec4 +unproject (vec2 screen, float z, float w) +{ + vec2 clip = screen / viewport; + vec2 device = clip * 2.0 - 1.0; + return vec4 (device * w, z, w); +} + +float +estimateScale (vec3 position, vec2 sPosition) +{ + vec4 view_pos = view * vec4 (position, 1.0); + vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width, + 0.0, 0.0); + vec2 screen_scale_pos = project (proj * scale_pos); + return distance (sPosition, screen_scale_pos); +} + +void +main (void) +{ + vec2 sLast = project (transform (last.xyz)); + vec2 sNext = project (transform (next.xyz)); + vec4 dCurrent = transform (current.xyz); + vec2 sCurrent = project (dCurrent); + float off = current.w; + + texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); + vBC = barycentric; + + // FIXME either n1 or n2 could be zero + vec2 n1 = normalize (sLast - sCurrent); + vec2 n2 = normalize (sCurrent - sNext); + // FIXME if n1 == -n2, the vector will be zero + vec2 n = normalize (n1 + n2); + + // rotate the normal by 90 degrees and scale by the desired width + vec2 dir = vec2 (n.y, -n.x) * off; + float scale = estimateScale (current.xyz, sCurrent); + vec2 pos = sCurrent + dir * scale; + + gl_Position = unproject (pos, dCurrent.z, dCurrent.w); +} From ddf4ff871f0c9e2a761cd4c93e88a6b1c6379d11 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Feb 2013 17:45:47 +0900 Subject: [PATCH 02/31] Make the entity param to trail functions non-const. Needed for adding trails to entities. --- include/QF/plugin/vid_render.h | 20 ++++++------ libs/video/renderer/gl/gl_dyn_part.c | 38 +++++++++++------------ libs/video/renderer/glsl/glsl_particles.c | 38 +++++++++++------------ libs/video/renderer/sw/sw_rpart.c | 18 +++++------ libs/video/renderer/sw32/sw32_rpart.c | 18 +++++------ 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index bdec285d1..04ee6e33b 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -42,14 +42,14 @@ struct skin_s; */ typedef struct vid_particle_funcs_s { - void (*R_RocketTrail) (const struct entity_s *ent); - void (*R_GrenadeTrail) (const struct entity_s *ent); - void (*R_BloodTrail) (const struct entity_s *ent); - void (*R_SlightBloodTrail) (const struct entity_s *ent); - void (*R_WizTrail) (const struct entity_s *ent); - void (*R_FlameTrail) (const struct entity_s *ent); - void (*R_VoorTrail) (const struct entity_s *ent); - void (*R_GlowTrail) (const struct entity_s *ent, int glow_color); + void (*R_RocketTrail) (struct entity_s *ent); + void (*R_GrenadeTrail) (struct entity_s *ent); + void (*R_BloodTrail) (struct entity_s *ent); + void (*R_SlightBloodTrail) (struct entity_s *ent); + void (*R_WizTrail) (struct entity_s *ent); + void (*R_FlameTrail) (struct entity_s *ent); + void (*R_VoorTrail) (struct entity_s *ent); + void (*R_GlowTrail) (struct entity_s *ent, int glow_color); void (*R_RunParticleEffect) (const vec3_t org, const vec3_t dir, int color, int count); @@ -67,8 +67,8 @@ typedef struct vid_particle_funcs_s { int colorLength); void (*R_LavaSplash) (const vec3_t org); void (*R_TeleportSplash) (const vec3_t org); - void (*R_DarkFieldParticles) (const struct entity_s *ent); - void (*R_EntityParticles) (const struct entity_s *ent); + void (*R_DarkFieldParticles) (struct entity_s *ent); + void (*R_EntityParticles) (struct entity_s *ent); void (*R_Particle_New) (ptype_t type, int texnum, const vec3_t org, float scale, const vec3_t vel, float die, diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 5b7f1a63a..77428573b 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -516,7 +516,7 @@ R_TeleportSplash_QF (const vec3_t org) } static void -R_RocketTrail_QF (const entity_t *ent) +R_RocketTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -550,7 +550,7 @@ R_RocketTrail_QF (const entity_t *ent) } static void -R_GrenadeTrail_QF (const entity_t *ent) +R_GrenadeTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -584,7 +584,7 @@ R_GrenadeTrail_QF (const entity_t *ent) } static void -R_BloodTrail_QF (const entity_t *ent) +R_BloodTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -624,7 +624,7 @@ R_BloodTrail_QF (const entity_t *ent) } static void -R_SlightBloodTrail_QF (const entity_t *ent) +R_SlightBloodTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -664,7 +664,7 @@ R_SlightBloodTrail_QF (const entity_t *ent) } static void -R_WizTrail_QF (const entity_t *ent) +R_WizTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -705,7 +705,7 @@ R_WizTrail_QF (const entity_t *ent) } static void -R_FlameTrail_QF (const entity_t *ent) +R_FlameTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -746,7 +746,7 @@ R_FlameTrail_QF (const entity_t *ent) } static void -R_VoorTrail_QF (const entity_t *ent) +R_VoorTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -779,7 +779,7 @@ R_VoorTrail_QF (const entity_t *ent) } static void -R_GlowTrail_QF (const entity_t *ent, int glow_color) +R_GlowTrail_QF (entity_t *ent, int glow_color) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -864,7 +864,7 @@ R_TeleportSplash_EE (const vec3_t org) } static void -R_RocketTrail_EE (const entity_t *ent) +R_RocketTrail_EE (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -899,7 +899,7 @@ R_RocketTrail_EE (const entity_t *ent) } static void -R_GrenadeTrail_EE (const entity_t *ent) +R_GrenadeTrail_EE (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -1130,7 +1130,7 @@ R_TeleportSplash_ID (const vec3_t org) } static void -R_DarkFieldParticles_ID (const entity_t *ent) +R_DarkFieldParticles_ID (entity_t *ent) { int i, j, k, l = 64; unsigned int rnd; @@ -1171,7 +1171,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) static vec3_t avelocities[NUMVERTEXNORMALS]; static void -R_EntityParticles_ID (const entity_t *ent) +R_EntityParticles_ID (entity_t *ent) { int i, j = NUMVERTEXNORMALS; float angle, sp, sy, cp, cy; // cr, sr @@ -1221,7 +1221,7 @@ R_EntityParticles_ID (const entity_t *ent) } static void -R_RocketTrail_ID (const entity_t *ent) +R_RocketTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1253,7 +1253,7 @@ R_RocketTrail_ID (const entity_t *ent) } static void -R_GrenadeTrail_ID (const entity_t *ent) +R_GrenadeTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1285,7 +1285,7 @@ R_GrenadeTrail_ID (const entity_t *ent) } static void -R_BloodTrail_ID (const entity_t *ent) +R_BloodTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1316,7 +1316,7 @@ R_BloodTrail_ID (const entity_t *ent) } static void -R_SlightBloodTrail_ID (const entity_t *ent) +R_SlightBloodTrail_ID (entity_t *ent) { float maxlen; float dist = 6.0, len = 0.0; @@ -1347,7 +1347,7 @@ R_SlightBloodTrail_ID (const entity_t *ent) } static void -R_WizTrail_ID (const entity_t *ent) +R_WizTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1384,7 +1384,7 @@ R_WizTrail_ID (const entity_t *ent) } static void -R_FlameTrail_ID (const entity_t *ent) +R_FlameTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1421,7 +1421,7 @@ R_FlameTrail_ID (const entity_t *ent) } static void -R_VoorTrail_ID (const entity_t *ent) +R_VoorTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index f1aa9f79b..9df306130 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -672,7 +672,7 @@ R_TeleportSplash_QF (const vec3_t org) } static void -R_RocketTrail_QF (const entity_t *ent) +R_RocketTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -706,7 +706,7 @@ R_RocketTrail_QF (const entity_t *ent) } static void -R_GrenadeTrail_QF (const entity_t *ent) +R_GrenadeTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -740,7 +740,7 @@ R_GrenadeTrail_QF (const entity_t *ent) } static void -R_BloodTrail_QF (const entity_t *ent) +R_BloodTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -780,7 +780,7 @@ R_BloodTrail_QF (const entity_t *ent) } static void -R_SlightBloodTrail_QF (const entity_t *ent) +R_SlightBloodTrail_QF (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -820,7 +820,7 @@ R_SlightBloodTrail_QF (const entity_t *ent) } static void -R_WizTrail_QF (const entity_t *ent) +R_WizTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -861,7 +861,7 @@ R_WizTrail_QF (const entity_t *ent) } static void -R_FlameTrail_QF (const entity_t *ent) +R_FlameTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -902,7 +902,7 @@ R_FlameTrail_QF (const entity_t *ent) } static void -R_VoorTrail_QF (const entity_t *ent) +R_VoorTrail_QF (entity_t *ent) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -935,7 +935,7 @@ R_VoorTrail_QF (const entity_t *ent) } static void -R_GlowTrail_QF (const entity_t *ent, int glow_color) +R_GlowTrail_QF (entity_t *ent, int glow_color) { float maxlen, origlen, percent; float dist = 3.0, len = 0.0; @@ -1020,7 +1020,7 @@ R_TeleportSplash_EE (const vec3_t org) } static void -R_RocketTrail_EE (const entity_t *ent) +R_RocketTrail_EE (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -1055,7 +1055,7 @@ R_RocketTrail_EE (const entity_t *ent) } static void -R_GrenadeTrail_EE (const entity_t *ent) +R_GrenadeTrail_EE (entity_t *ent) { float dist, maxlen, origlen, percent, pscale, pscalenext; float len = 0.0; @@ -1286,7 +1286,7 @@ R_TeleportSplash_ID (const vec3_t org) } static void -R_DarkFieldParticles_ID (const entity_t *ent) +R_DarkFieldParticles_ID (entity_t *ent) { int i, j, k, l = 64; unsigned int rnd; @@ -1327,7 +1327,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) static vec3_t avelocities[NUMVERTEXNORMALS]; static void -R_EntityParticles_ID (const entity_t *ent) +R_EntityParticles_ID (entity_t *ent) { int i, j = NUMVERTEXNORMALS; float angle, sp, sy, cp, cy; // cr, sr @@ -1375,7 +1375,7 @@ R_EntityParticles_ID (const entity_t *ent) } static void -R_RocketTrail_ID (const entity_t *ent) +R_RocketTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1407,7 +1407,7 @@ R_RocketTrail_ID (const entity_t *ent) } static void -R_GrenadeTrail_ID (const entity_t *ent) +R_GrenadeTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1439,7 +1439,7 @@ R_GrenadeTrail_ID (const entity_t *ent) } static void -R_BloodTrail_ID (const entity_t *ent) +R_BloodTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1470,7 +1470,7 @@ R_BloodTrail_ID (const entity_t *ent) } static void -R_SlightBloodTrail_ID (const entity_t *ent) +R_SlightBloodTrail_ID (entity_t *ent) { float maxlen; float dist = 6.0, len = 0.0; @@ -1501,7 +1501,7 @@ R_SlightBloodTrail_ID (const entity_t *ent) } static void -R_WizTrail_ID (const entity_t *ent) +R_WizTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1538,7 +1538,7 @@ R_WizTrail_ID (const entity_t *ent) } static void -R_FlameTrail_ID (const entity_t *ent) +R_FlameTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; @@ -1575,7 +1575,7 @@ R_FlameTrail_ID (const entity_t *ent) } static void -R_VoorTrail_ID (const entity_t *ent) +R_VoorTrail_ID (entity_t *ent) { float maxlen; float dist = 3.0, len = 0.0; diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index aeb2fa904..4e113cc5b 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -375,7 +375,7 @@ R_TeleportSplash_QF (const vec3_t org) } static void -R_DarkFieldParticles_ID (const entity_t *ent) +R_DarkFieldParticles_ID (entity_t *ent) { int i, j, k; unsigned int rnd; @@ -424,7 +424,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) static vec3_t avelocities[NUMVERTEXNORMALS]; static void -R_EntityParticles_ID (const entity_t *ent) +R_EntityParticles_ID (entity_t *ent) { int i; float angle, sp, sy, cp, cy; // cr, sr @@ -480,7 +480,7 @@ R_EntityParticles_ID (const entity_t *ent) } static void -R_RocketTrail_QF (const entity_t *ent) +R_RocketTrail_QF (entity_t *ent) { float len; int j; @@ -519,7 +519,7 @@ R_RocketTrail_QF (const entity_t *ent) } static void -R_GrenadeTrail_QF (const entity_t *ent) +R_GrenadeTrail_QF (entity_t *ent) { float len; int j; @@ -558,7 +558,7 @@ R_GrenadeTrail_QF (const entity_t *ent) } static void -R_BloodTrail_QF (const entity_t *ent) +R_BloodTrail_QF (entity_t *ent) { float len; int j; @@ -597,7 +597,7 @@ R_BloodTrail_QF (const entity_t *ent) } static void -R_SlightBloodTrail_QF (const entity_t *ent) +R_SlightBloodTrail_QF (entity_t *ent) { float len; int j; @@ -635,7 +635,7 @@ R_SlightBloodTrail_QF (const entity_t *ent) } static void -R_WizTrail_QF (const entity_t *ent) +R_WizTrail_QF (entity_t *ent) { float len; particle_t *p; @@ -682,7 +682,7 @@ R_WizTrail_QF (const entity_t *ent) } static void -R_FlameTrail_QF (const entity_t *ent) +R_FlameTrail_QF (entity_t *ent) { float len; particle_t *p; @@ -729,7 +729,7 @@ R_FlameTrail_QF (const entity_t *ent) } static void -R_VoorTrail_QF (const entity_t *ent) +R_VoorTrail_QF (entity_t *ent) { float len; int j; diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 5591b9929..0ba04ca1b 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -322,7 +322,7 @@ R_TeleportSplash_QF (const vec3_t org) } static void -R_DarkFieldParticles_ID (const entity_t *ent) +R_DarkFieldParticles_ID (entity_t *ent) { int i, j, k; unsigned int rnd; @@ -369,7 +369,7 @@ R_DarkFieldParticles_ID (const entity_t *ent) static vec3_t avelocities[NUMVERTEXNORMALS]; static void -R_EntityParticles_ID (const entity_t *ent) +R_EntityParticles_ID (entity_t *ent) { int i; float angle, sp, sy, cp, cy; // cr, sr @@ -493,7 +493,7 @@ R_LightningBloodEffect_QF (const vec3_t org) } static void -R_RocketTrail_QF (const entity_t *ent) +R_RocketTrail_QF (entity_t *ent) { float len; int j; @@ -532,7 +532,7 @@ R_RocketTrail_QF (const entity_t *ent) } static void -R_GrenadeTrail_QF (const entity_t *ent) +R_GrenadeTrail_QF (entity_t *ent) { float len; int j; @@ -571,7 +571,7 @@ R_GrenadeTrail_QF (const entity_t *ent) } static void -R_BloodTrail_QF (const entity_t *ent) +R_BloodTrail_QF (entity_t *ent) { float len; int j; @@ -610,7 +610,7 @@ R_BloodTrail_QF (const entity_t *ent) } static void -R_SlightBloodTrail_QF (const entity_t *ent) +R_SlightBloodTrail_QF (entity_t *ent) { float len; int j; @@ -648,7 +648,7 @@ R_SlightBloodTrail_QF (const entity_t *ent) } static void -R_WizTrail_QF (const entity_t *ent) +R_WizTrail_QF (entity_t *ent) { float len; particle_t *p; @@ -695,7 +695,7 @@ R_WizTrail_QF (const entity_t *ent) } static void -R_FlameTrail_QF (const entity_t *ent) +R_FlameTrail_QF (entity_t *ent) { float len; particle_t *p; @@ -742,7 +742,7 @@ R_FlameTrail_QF (const entity_t *ent) } static void -R_VoorTrail_QF (const entity_t *ent) +R_VoorTrail_QF (entity_t *ent) { float len; int j; From bd3647d67120967b4d3d0b821fbfb96d16df9f80 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Feb 2013 22:17:38 +0900 Subject: [PATCH 03/31] Put the trail frag shader into debug mode. This draws the wire-frame of the trail. Yay Florian Boesch. --- libs/video/renderer/glsl/trail.frag | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libs/video/renderer/glsl/trail.frag b/libs/video/renderer/glsl/trail.frag index 2dd3f2b31..22d310291 100644 --- a/libs/video/renderer/glsl/trail.frag +++ b/libs/video/renderer/glsl/trail.frag @@ -3,8 +3,24 @@ uniform sampler2D smoke; varying vec2 texcoord; varying vec3 vBC; +#if 0 void main (void) { gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); } +#else +float +edgeFactor (void) +{ + vec3 d = fwidth (vBC); + vec3 a3 = smoothstep (vec3 (0.0), d * 1.5, vBC); + return min (min (a3.x, a3.y), a3.z); +} + +void +main (void) +{ + gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); +} +#endif From 2fbab084a178e6393649a252a4fa25321c6fe2b9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 21 Feb 2013 22:19:19 +0900 Subject: [PATCH 04/31] Build and draw solid trails for rockets. And lava balls (handy test, actually). --- include/QF/render.h | 2 + libs/video/renderer/glsl/glsl_particles.c | 277 +++++++++++++++++++++- 2 files changed, 278 insertions(+), 1 deletion(-) diff --git a/include/QF/render.h b/include/QF/render.h index cc08c3800..55514632b 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -106,6 +106,8 @@ typedef struct entity_s { int fullbright; float min_light; + struct trail_s *trail; + // FIXME: could turn these into a union int trivial_accept; struct mnode_s *topnode; // for bmodels, first world node that diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 9df306130..6a4b59358 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -40,6 +40,7 @@ #include +#include "QF/alloc.h" #include "QF/cmd.h" #include "QF/cvar.h" #include "QF/image.h" @@ -174,6 +175,54 @@ static struct { {"smoke", 1}, }; +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; +} trailvtx_t; + +static trail_t *free_trails; +static trail_t *active_trails; +static particle_t *free_points; + +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); +} + inline static void particle_new (ptype_t type, int texnum, const vec3_t org, float scale, const vec3_t vel, float die, int color, float alpha, float ramp) @@ -671,6 +720,57 @@ R_TeleportSplash_QF (const vec3_t org) } } +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) { + ent->trail = new_trail (); + ent->trail->next = active_trails; + ent->trail->prev = &active_trails; + ent->trail->owner = &ent->trail; + if (active_trails) + active_trails->prev = &ent->trail->next; + active_trails = ent->trail; + } + + 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_point (); + VectorCopy (old_origin, point->org); + point->color = 12 + (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->type = pt_smoke; + point->die = vr_data.realtime + 2.0 - percent * 2.0; + point->ramp = 0.0; + point->phys = R_ParticlePhysics (point->type); + + *ent->trail->head = point; + ent->trail->head = &point->next; + ent->trail->num_points++; + + len += dist; + VectorMultAdd (old_origin, len, vec, old_origin); + pscale = pscalenext; + } +} + static void R_RocketTrail_QF (entity_t *ent) { @@ -1606,6 +1706,150 @@ R_VoorTrail_ID (entity_t *ent) } } +static inline void +set_vertex (trailvtx_t *v, const particle_t *point, float w, const vec3_t bary, + float off) +{ + VectorCopy (point->org, v->vertex); + VectorCopy (bary, v->bary); + v->vertex[3] = w; + v->texoff = off; +} + +static void +count_points (int *num_verts, int *num_elements) +{ + trail_t *trail; + + *num_verts = 0; + *num_elements = 0; + for (trail = active_trails; trail; trail = trail->next) { + if (trail->num_points < 2) + continue; + // +2 for an extra point at either end of the strip + *num_verts += (trail->num_points + 2) * 2; + *num_elements += trail->num_points * 2; + } +} + +static void +build_verts (trailvtx_t *v, GLushort *e) +{ + trail_t *trail; + int index = 0; + particle_t *point, *last_point = 0; + float bary[] = {0, 0, 1, 0, 0, 1, 0, 0}; + int bind = 0; + + for (trail = active_trails; trail; trail = trail->next) { + if (trail->num_points < 2) + continue; + point = trail->points; + set_vertex (v++, point, 1, bary + bind++, index/2); + set_vertex (v++, point, -1, bary + bind++, index/2); + bind %= 3; + for (; point; point = point->next) { + set_vertex (v++, point, 1, bary + bind++, index/2 + 1); + set_vertex (v++, point, -1, bary + bind++, index/2 + 1); + bind %= 3; + *e++ = index++; + *e++ = index++; + last_point = point; + point->phys (point); + } + set_vertex (v++, last_point, 1, bary + bind++, index/2 + 1); + set_vertex (v++, last_point, -1, bary + bind++, index/2 + 1); + index += 4; + } +} + +static void +expire_trails (void) +{ + trail_t *trail, *next_trail; + + for (trail = active_trails; 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 num_elements; + trailvtx_t *verts; + GLushort *elements; + + count_points (&num_verts, &num_elements); + if (!num_elements) + return; + + verts = alloca (num_verts * sizeof (trailvtx_t)); + elements = alloca (num_verts * sizeof (GLushort)); + build_verts (verts, elements); + + qfeglDisable (GL_CULL_FACE); + + qfeglUseProgram (trail.program); + qfeglEnableVertexAttribArray (trail.last.location); + qfeglEnableVertexAttribArray (trail.current.location); + qfeglEnableVertexAttribArray (trail.next.location); + qfeglEnableVertexAttribArray (trail.barycentric.location); + qfeglEnableVertexAttribArray (trail.texoff.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); + 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); + + for (trl = active_trails; trl; trl = trl->next) { + int count; + if (trl->num_points < 2) + continue; + count = trl->num_points * 2; + qfeglDrawElements (GL_TRIANGLE_STRIP, count, GL_UNSIGNED_SHORT, + elements); + elements += count; + } + + qfeglDisableVertexAttribArray (trail.last.location); + qfeglDisableVertexAttribArray (trail.current.location); + qfeglDisableVertexAttribArray (trail.next.location); + qfeglDisableVertexAttribArray (trail.barycentric.location); + qfeglDisableVertexAttribArray (trail.texoff.location); + + qfeglEnable (GL_CULL_FACE); + + expire_trails (); +} + static void draw_qf_particles (void) { @@ -1839,6 +2083,7 @@ draw_id_particles (void) void glsl_R_DrawParticles (void) { + draw_trails (); if (!r_particles->int_val || !numparticles) return; if (r_particles_style->int_val) { @@ -1848,6 +2093,34 @@ glsl_R_DrawParticles (void) } } +static vid_particle_funcs_t particles_trail = { + R_RocketTrail_trail, + R_GrenadeTrail_QF, + R_BloodTrail_QF, + R_SlightBloodTrail_QF, + R_WizTrail_QF, + R_FlameTrail_QF, + R_VoorTrail_QF, + R_GlowTrail_QF, + R_RunParticleEffect_QF, + R_BloodPuffEffect_QF, + R_GunshotEffect_QF, + R_LightningBloodEffect_QF, + R_SpikeEffect_QF, + R_KnightSpikeEffect_QF, + R_SuperSpikeEffect_QF, + R_WizSpikeEffect_QF, + R_BlobExplosion_QF, + R_ParticleExplosion_QF, + R_ParticleExplosion2_QF, + R_LavaSplash_QF, + R_TeleportSplash_QF, + R_DarkFieldParticles_ID, + R_EntityParticles_ID, + R_Particle_New, + R_Particle_NewRandom, +}; + static vid_particle_funcs_t particles_QF = { R_RocketTrail_QF, R_GrenadeTrail_QF, @@ -1971,8 +2244,10 @@ glsl_r_easter_eggs_f (cvar_t *var) glsl_vid_render_funcs.particles = &particles_ID_egg; } } else if (r_particles_style) { - if (r_particles_style->int_val) { + if (r_particles_style->int_val > 1) { glsl_vid_render_funcs.particles = &particles_QF; + } else if (r_particles_style->int_val) { + glsl_vid_render_funcs.particles = &particles_trail; } else { glsl_vid_render_funcs.particles = &particles_ID; } From 1a067124058078bba522ad2e72f025f2eb76dfdc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Feb 2013 18:37:24 +0900 Subject: [PATCH 05/31] Handle the singularities on the trail vectors. They're actually guaranteed for the first and last segments due to the first and last points being duplicated in the buffer (simplifies design). This also handles the rare case where a vector appears to go directly into or out of the screen. Everything works nicely if only one of n1 or n2 is 0, and for the very rare case of both n1 and n2 being 0, then a final normal of 0 is reasonable. --- libs/video/renderer/glsl/trail.vert | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/libs/video/renderer/glsl/trail.vert b/libs/video/renderer/glsl/trail.vert index f942db8c2..f722e41d9 100644 --- a/libs/video/renderer/glsl/trail.vert +++ b/libs/video/renderer/glsl/trail.vert @@ -44,6 +44,7 @@ estimateScale (vec3 position, vec2 sPosition) void main (void) { + vec2 t, n1, n2, n; vec2 sLast = project (transform (last.xyz)); vec2 sNext = project (transform (next.xyz)); vec4 dCurrent = transform (current.xyz); @@ -53,11 +54,21 @@ main (void) texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); vBC = barycentric; - // FIXME either n1 or n2 could be zero - vec2 n1 = normalize (sLast - sCurrent); - vec2 n2 = normalize (sCurrent - sNext); - // FIXME if n1 == -n2, the vector will be zero - vec2 n = normalize (n1 + n2); + t = sLast - sCurrent; + n1 = vec2 (0.0); + if (dot (t, t) > 0.001) + n1 = normalize (t); + t = sCurrent - sNext; + n2 = vec2 (0.0); + if (dot (t, t) > 0.001) + n2 = normalize (t); + n = vec2 (0.0); + if (n1 != -n2) + n = normalize (n1 + n2); + else if (dot (n1, n1) > 0.001) + n = n1; + else if (dot (n2, n2) > 0.001) + n = n2; // rotate the normal by 90 degrees and scale by the desired width vec2 dir = vec2 (n.y, -n.x) * off; From bb022bc4fc7a5656e741a2ab6a4d53237fd1e384 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 22 Feb 2013 19:16:42 +0900 Subject: [PATCH 06/31] Reverse the trail vertex order. That webgl app was designed for GL's default of CCW for front faces, but quake wants CW. Now the disable/enable of face culling isn't necessary. --- libs/video/renderer/glsl/glsl_particles.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 6a4b59358..cc6df23eb 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -1745,20 +1745,20 @@ build_verts (trailvtx_t *v, GLushort *e) if (trail->num_points < 2) continue; point = trail->points; - set_vertex (v++, point, 1, bary + bind++, index/2); set_vertex (v++, point, -1, bary + bind++, index/2); + set_vertex (v++, point, 1, bary + bind++, index/2); bind %= 3; for (; point; point = point->next) { - set_vertex (v++, point, 1, bary + bind++, index/2 + 1); set_vertex (v++, point, -1, bary + bind++, index/2 + 1); + set_vertex (v++, point, 1, bary + bind++, index/2 + 1); bind %= 3; *e++ = index++; *e++ = index++; last_point = point; point->phys (point); } - set_vertex (v++, last_point, 1, bary + bind++, index/2 + 1); set_vertex (v++, last_point, -1, bary + bind++, index/2 + 1); + set_vertex (v++, last_point, 1, bary + bind++, index/2 + 1); index += 4; } } @@ -1803,8 +1803,6 @@ draw_trails (void) elements = alloca (num_verts * sizeof (GLushort)); build_verts (verts, elements); - qfeglDisable (GL_CULL_FACE); - qfeglUseProgram (trail.program); qfeglEnableVertexAttribArray (trail.last.location); qfeglEnableVertexAttribArray (trail.current.location); @@ -1845,8 +1843,6 @@ draw_trails (void) qfeglDisableVertexAttribArray (trail.barycentric.location); qfeglDisableVertexAttribArray (trail.texoff.location); - qfeglEnable (GL_CULL_FACE); - expire_trails (); } From 299f305453b2cbd4f6a6d9943066ffa786dfeb32 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 28 Jan 2014 16:45:36 +0900 Subject: [PATCH 07/31] Update the trails code to use shader effects. Trails was actually the reason I started that project. This is just cleanup after rebasing. --- libs/video/renderer/glsl/Makefile.am | 4 +- libs/video/renderer/glsl/glsl_particles.c | 48 ++++++---- libs/video/renderer/glsl/quakeforge.glsl | 111 ++++++++++++++++++++++ libs/video/renderer/glsl/trail.frag | 26 ----- libs/video/renderer/glsl/trail.vert | 79 --------------- 5 files changed, 141 insertions(+), 127 deletions(-) delete mode 100644 libs/video/renderer/glsl/trail.frag delete mode 100644 libs/video/renderer/glsl/trail.vert diff --git a/libs/video/renderer/glsl/Makefile.am b/libs/video/renderer/glsl/Makefile.am index 4072d5ac0..ca8f4314a 100644 --- a/libs/video/renderer/glsl/Makefile.am +++ b/libs/video/renderer/glsl/Makefile.am @@ -3,8 +3,8 @@ AUTOMAKE_OPTIONS= foreign AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include $(GLX_CFLAGS) -shader_src= quakeforge.glsl trail.frag trail.vert -shader_gen= quakeforge.slc trail.fc trail.vc +shader_src= quakeforge.glsl +shader_gen= quakeforge.slc glsl_src = \ glsl_alias.c glsl_bsp.c glsl_draw.c glsl_fog.c glsl_iqm.c glsl_lightmap.c \ diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index cc6df23eb..6107a5fd9 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -107,13 +107,17 @@ static const char *particle_textured_frag_effects[] = 0 }; -static const char trail_vert[] = -#include "trail.vc" -; +static const char *particle_trail_vert_effects[] = +{ + "QuakeForge.Vertex.particle.trail", + 0 +}; -static const char trail_frag[] = -#include "trail.fc" -; +static const char *particle_trail_frag_effects[] = +{ + "QuakeForge.Fragment.particle.trail", + 0 +}; static struct { int program; @@ -190,9 +194,9 @@ typedef struct trailvtx_s { float texoff; } trailvtx_t; -static trail_t *free_trails; -static trail_t *active_trails; -static particle_t *free_points; +static trail_t *trails_freelist; +static trail_t *trails_active; +static particle_t *points_freelist; static trail_t * new_trail (void) @@ -350,8 +354,10 @@ glsl_R_InitParticles (void) GLSL_FreeShader (vert_shader); GLSL_FreeShader (frag_shader); - vert = GLSL_CompileShader ("trail.vert", trail_vert, GL_VERTEX_SHADER); - frag = GLSL_CompileShader ("trail.frag", trail_frag, GL_FRAGMENT_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); @@ -363,6 +369,8 @@ glsl_R_InitParticles (void) GLSL_ResolveShaderParam (trail.program, &trail.barycentric); GLSL_ResolveShaderParam (trail.program, &trail.texoff); GLSL_ResolveShaderParam (trail.program, &trail.smoke); + GLSL_FreeShader (vert_shader); + GLSL_FreeShader (frag_shader); memset (data, 0, sizeof (data)); qfeglGenTextures (1, &part_tex); @@ -730,12 +738,12 @@ R_RocketTrail_trail (entity_t *ent) if (!ent->trail) { ent->trail = new_trail (); - ent->trail->next = active_trails; - ent->trail->prev = &active_trails; + ent->trail->next = trails_active; + ent->trail->prev = &trails_active; ent->trail->owner = &ent->trail; - if (active_trails) - active_trails->prev = &ent->trail->next; - active_trails = ent->trail; + if (trails_active) + trails_active->prev = &ent->trail->next; + trails_active = ent->trail; } VectorCopy (ent->old_origin, old_origin); @@ -1723,7 +1731,7 @@ count_points (int *num_verts, int *num_elements) *num_verts = 0; *num_elements = 0; - for (trail = active_trails; trail; trail = trail->next) { + for (trail = trails_active; trail; trail = trail->next) { if (trail->num_points < 2) continue; // +2 for an extra point at either end of the strip @@ -1741,7 +1749,7 @@ build_verts (trailvtx_t *v, GLushort *e) float bary[] = {0, 0, 1, 0, 0, 1, 0, 0}; int bind = 0; - for (trail = active_trails; trail; trail = trail->next) { + for (trail = trails_active; trail; trail = trail->next) { if (trail->num_points < 2) continue; point = trail->points; @@ -1768,7 +1776,7 @@ expire_trails (void) { trail_t *trail, *next_trail; - for (trail = active_trails; trail; 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; @@ -1827,7 +1835,7 @@ draw_trails (void) qfeglVertexAttribPointer (trail.texoff.location, 1, GL_FLOAT, 0, sizeof (trailvtx_t), &verts[0].texoff); - for (trl = active_trails; trl; trl = trl->next) { + for (trl = trails_active; trl; trl = trl->next) { int count; if (trl->num_points < 2) continue; diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index e346b31af..9cff7684e 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -551,3 +551,114 @@ main (void) col = texture2D (texture, st) * color * vec4 (l, 1.0); gl_FragColor = fogBlend (col); } + +-- Vertex.particle.trail + +attribute vec4 last, current, next; +attribute vec3 barycentric; +attribute float texoff; + +uniform mat4 proj, view; +uniform vec2 viewport; +uniform float width; + +varying vec2 texcoord; +varying vec3 vBC; + +vec4 +transform (vec3 coord) +{ + return proj * view * vec4 (coord, 1.0); +} + +vec2 +project (vec4 coord) +{ + vec3 device = coord.xyz / coord.w; + vec2 clip = (device * 0.5 + 0.5).xy; + return clip * viewport; +} + +vec4 +unproject (vec2 screen, float z, float w) +{ + vec2 clip = screen / viewport; + vec2 device = clip * 2.0 - 1.0; + return vec4 (device * w, z, w); +} + +float +estimateScale (vec3 position, vec2 sPosition) +{ + vec4 view_pos = view * vec4 (position, 1.0); + vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width, + 0.0, 0.0); + vec2 screen_scale_pos = project (proj * scale_pos); + return distance (sPosition, screen_scale_pos); +} + +void +main (void) +{ + vec2 t, n1, n2, n; + vec2 sLast = project (transform (last.xyz)); + vec2 sNext = project (transform (next.xyz)); + vec4 dCurrent = transform (current.xyz); + vec2 sCurrent = project (dCurrent); + float off = current.w; + + texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); + vBC = barycentric; + + t = sLast - sCurrent; + n1 = vec2 (0.0); + if (dot (t, t) > 0.001) + n1 = normalize (t); + t = sCurrent - sNext; + n2 = vec2 (0.0); + if (dot (t, t) > 0.001) + n2 = normalize (t); + n = vec2 (0.0); + if (n1 != -n2) + n = normalize (n1 + n2); + else if (dot (n1, n1) > 0.001) + n = n1; + else if (dot (n2, n2) > 0.001) + n = n2; + + // rotate the normal by 90 degrees and scale by the desired width + vec2 dir = vec2 (n.y, -n.x) * off; + float scale = estimateScale (current.xyz, sCurrent); + vec2 pos = sCurrent + dir * scale; + + gl_Position = unproject (pos, dCurrent.z, dCurrent.w); +} + +-- Fragment.particle.trail + +uniform sampler2D smoke; + +varying vec2 texcoord; +varying vec3 vBC; + +#if 0 +void +main (void) +{ + gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); +} +#else +float +edgeFactor (void) +{ + vec3 d = fwidth (vBC); + vec3 a3 = smoothstep (vec3 (0.0), d * 1.5, vBC); + return min (min (a3.x, a3.y), a3.z); +} + +void +main (void) +{ + gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); +} +#endif diff --git a/libs/video/renderer/glsl/trail.frag b/libs/video/renderer/glsl/trail.frag deleted file mode 100644 index 22d310291..000000000 --- a/libs/video/renderer/glsl/trail.frag +++ /dev/null @@ -1,26 +0,0 @@ -uniform sampler2D smoke; - -varying vec2 texcoord; -varying vec3 vBC; - -#if 0 -void -main (void) -{ - gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); -} -#else -float -edgeFactor (void) -{ - vec3 d = fwidth (vBC); - vec3 a3 = smoothstep (vec3 (0.0), d * 1.5, vBC); - return min (min (a3.x, a3.y), a3.z); -} - -void -main (void) -{ - gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); -} -#endif diff --git a/libs/video/renderer/glsl/trail.vert b/libs/video/renderer/glsl/trail.vert deleted file mode 100644 index f722e41d9..000000000 --- a/libs/video/renderer/glsl/trail.vert +++ /dev/null @@ -1,79 +0,0 @@ -attribute vec4 last, current, next; -attribute vec3 barycentric; -attribute float texoff; - -uniform mat4 proj, view; -uniform vec2 viewport; -uniform float width; - -varying vec2 texcoord; -varying vec3 vBC; - -vec4 -transform (vec3 coord) -{ - return proj * view * vec4 (coord, 1.0); -} - -vec2 -project (vec4 coord) -{ - vec3 device = coord.xyz / coord.w; - vec2 clip = (device * 0.5 + 0.5).xy; - return clip * viewport; -} - -vec4 -unproject (vec2 screen, float z, float w) -{ - vec2 clip = screen / viewport; - vec2 device = clip * 2.0 - 1.0; - return vec4 (device * w, z, w); -} - -float -estimateScale (vec3 position, vec2 sPosition) -{ - vec4 view_pos = view * vec4 (position, 1.0); - vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width, - 0.0, 0.0); - vec2 screen_scale_pos = project (proj * scale_pos); - return distance (sPosition, screen_scale_pos); -} - -void -main (void) -{ - vec2 t, n1, n2, n; - vec2 sLast = project (transform (last.xyz)); - vec2 sNext = project (transform (next.xyz)); - vec4 dCurrent = transform (current.xyz); - vec2 sCurrent = project (dCurrent); - float off = current.w; - - texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); - vBC = barycentric; - - t = sLast - sCurrent; - n1 = vec2 (0.0); - if (dot (t, t) > 0.001) - n1 = normalize (t); - t = sCurrent - sNext; - n2 = vec2 (0.0); - if (dot (t, t) > 0.001) - n2 = normalize (t); - n = vec2 (0.0); - if (n1 != -n2) - n = normalize (n1 + n2); - else if (dot (n1, n1) > 0.001) - n = n1; - else if (dot (n2, n2) > 0.001) - n = n2; - - // rotate the normal by 90 degrees and scale by the desired width - vec2 dir = vec2 (n.y, -n.x) * off; - float scale = estimateScale (current.xyz, sCurrent); - vec2 pos = sCurrent + dir * scale; - - gl_Position = unproject (pos, dCurrent.z, dCurrent.w); -} From e60132a9b06781afa01854ddc3e02d91a4876acd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 29 Jan 2014 14:12:27 +0900 Subject: [PATCH 08/31] Add a copyright block to quakeforge.glsl --- libs/video/renderer/glsl/quakeforge.glsl | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index 9cff7684e..f214cfd02 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -1,3 +1,30 @@ +quakeforge.glsl + +Builtin QuakeForge GLSL shaders. + +Copyright (C) 2013 Bill Currie + +Author: Bill Currie +Date: 2013/05/12 + +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 + -- Math.const const float PI = 3.14159265; From 8310f2aeeee9671f681d6b70c908704096ca7934 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 29 Jan 2014 15:13:40 +0900 Subject: [PATCH 09/31] Add Stefan Gustavson's glsl noise shaders. --- libs/video/renderer/glsl/Makefile.am | 6 +- libs/video/renderer/glsl/sgustavson.glsl | 608 +++++++++++++++++++++ libs/video/renderer/glsl/vid_common_glsl.c | 5 + 3 files changed, 616 insertions(+), 3 deletions(-) create mode 100644 libs/video/renderer/glsl/sgustavson.glsl diff --git a/libs/video/renderer/glsl/Makefile.am b/libs/video/renderer/glsl/Makefile.am index ca8f4314a..71c9d37e2 100644 --- a/libs/video/renderer/glsl/Makefile.am +++ b/libs/video/renderer/glsl/Makefile.am @@ -3,8 +3,8 @@ AUTOMAKE_OPTIONS= foreign AM_CFLAGS= @PREFER_PIC@ AM_CPPFLAGS= -I$(top_srcdir)/include $(GLX_CFLAGS) -shader_src= quakeforge.glsl -shader_gen= quakeforge.slc +shader_src= sgustavson.glsl quakeforge.glsl +shader_gen= sgustavson.slc quakeforge.slc glsl_src = \ glsl_alias.c glsl_bsp.c glsl_draw.c glsl_fog.c glsl_iqm.c glsl_lightmap.c \ @@ -16,7 +16,7 @@ BUILT_SOURCES= $(shader_gen) SUFFICES=.frag .vert .fc .vc .slc .glsl .glsl.slc: - sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ .frag.fc: sed -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ .vert.vc: diff --git a/libs/video/renderer/glsl/sgustavson.glsl b/libs/video/renderer/glsl/sgustavson.glsl new file mode 100644 index 000000000..59aa9f5f2 --- /dev/null +++ b/libs/video/renderer/glsl/sgustavson.glsl @@ -0,0 +1,608 @@ +Note that the GPL covers only the arrangement in this file. The actual code +is covered by the MIT licence (see LICENCE.txt below). + +This file is just all the shader code presented by Stefan Gustavson +collected into one file and split into useable sections with redundant +code removed. + +-- + +sgustavson.glsl + +GLSL noise functions + +Copyright (C) 2014 Bill Currie + +Author: Bill Currie +Date: 2014/01/29 + +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 + +-- LICENCE.txt + +Copyright (C) 2011 by Stefan Gustavson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-- Math.permute + +vec4 permute(vec4 x) +{ + return mod(((x*34.0)+1.0)*x, 289.0); +} + +-- Math.InvSqrt + +vec4 taylorInvSqrt(vec4 r) +{ + return 1.79284291400159 - 0.85373472095314 * r; +} + +-- Noise.simplex + +// Description : Array and textureless GLSL 3D simplex noise function. +// Author : Ian McEwan, Ashima Arts. +// Maintainer : ijm +// Lastmod : 20110409 (stegu) +// License : Copyright (C) 2011 Ashima Arts. All rights reserved. +// Distributed under the MIT License. See LICENSE file. + +#version 120 + +float snoise(vec3 v) +{ + const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy) ); + vec3 x0 = v - i + dot(i, C.xxx) ; + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0. + 0.0 * C + vec3 x1 = x0 - i1 + 1.0 * C.xxx; + vec3 x2 = x0 - i2 + 2.0 * C.xxx; + vec3 x3 = x0 - 1. + 3.0 * C.xxx; + + // Permutations + i = mod(i, 289.0 ); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + + // Gradients + // ( N*N points uniformly over a square, mapped onto an octahedron.) + float n_ = 1.0/7.0; // N=7 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ *ns.x + ns.yyyy; + vec4 y = y_ *ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0)*2.0 + 1.0; + vec4 s1 = floor(b1)*2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; + + vec3 p0 = vec3(a0.xy,h.x); + vec3 p1 = vec3(a0.zw,h.y); + vec3 p2 = vec3(a1.xy,h.z); + vec3 p3 = vec3(a1.zw,h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); + m = m * m; + return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), + dot(p2,x2), dot(p3,x3) ) ); +} + +-- Vertex.simplex + +#version 120 + +uniform float time; +varying vec3 vTexCoord3D; + +void main(void) { + vTexCoord3D = gl_Vertex.xyz * 4.0 + vec3(0.0, 0.0, time); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +-- Fragment.simplex + +varying vec3 vTexCoord3D; +void main( void ) +{ + float n = snoise(vTexCoord3D); + + gl_FragColor = vec4(0.5 + 0.6 * vec3(n, n, n), 1.0); +} + +-- Vertex.flame + +#version 120 + +uniform float time; +varying vec3 vTexCoord3D; + +void main(void) { + vTexCoord3D = gl_Vertex.xyz * 2.0 + vec3(0.0, 0.0, -time); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +-- Fragement.flame + +varying vec3 vTexCoord3D; +void main( void ) +{ + float n = abs(snoise(vTexCoord3D)); + n += 0.5 * abs(snoise(vTexCoord3D * 2.0)); + n += 0.25 * abs(snoise(vTexCoord3D * 4.0)); + n += 0.125 * abs(snoise(vTexCoord3D * 8.0)); + + gl_FragColor = vec4(vec3(1.5-n, 1.0-n, 0.5-n), 1.0); +} + +-- Noise.flow + +// GLSL implementation of 2D "flow noise" as presented +// by Ken Perlin and Fabrice Neyret at Siggraph 2001. +// (2D simplex noise with analytic derivatives and +// in-plane rotation of generating gradients, +// in a fractal sum where higher frequencies are +// displaced (advected) by lower frequencies in the +// direction of their gradient. For details, please +// refer to the 2001 paper "Flow Noise" by Perlin and Neyret.) +// +// Author: Stefan Gustavson (stefan.gustavson@liu.se) +// Distributed under the terms of the MIT license. +// See LICENSE file for details. +// + +// Helper constants +#define F2 0.366025403 +#define G2 0.211324865 +#define K 0.0243902439 // 1/41 + +// Gradient mapping with an extra rotation. +vec2 grad2(vec2 p, float rot) { +#if 1 +// Map from a line to a diamond such that a shift maps to a rotation. + float u = permute(permute(p.x) + p.y) * K + rot; // Rotate by shift + u = 4.0 * fract(u) - 2.0; + return vec2(abs(u)-1.0, abs(abs(u+1.0)-2.0)-1.0); +#else +#define TWOPI 6.28318530718 +// For more isotropic gradients, sin/cos can be used instead. + float u = permute(permute(p.x) + p.y) * K + rot; // Rotate by shift + u = fract(u) * TWOPI; + return vec2(cos(u), sin(u)); +#endif +} + +float srdnoise(in vec2 P, in float rot, out vec2 grad) { + + // Transform input point to the skewed simplex grid + vec2 Ps = P + dot(P, vec2(F2)); + + // Round down to simplex origin + vec2 Pi = floor(Ps); + + // Transform simplex origin back to (x,y) system + vec2 P0 = Pi - dot(Pi, vec2(G2)); + + // Find (x,y) offsets from simplex origin to first corner + vec2 v0 = P - P0; + + // Pick (+x, +y) or (+y, +x) increment sequence + vec2 i1 = (v0.x > v0.y) ? vec2(1.0, 0.0) : vec2 (0.0, 1.0); + + // Determine the offsets for the other two corners + vec2 v1 = v0 - i1 + G2; + vec2 v2 = v0 - 1.0 + 2.0 * G2; + + // Wrap coordinates at 289 to avoid float precision problems + Pi = mod(Pi, 289.0); + + // Calculate the circularly symmetric part of each noise wiggle + vec3 t = max(0.5 - vec3(dot(v0,v0), dot(v1,v1), dot(v2,v2)), 0.0); + vec3 t2 = t*t; + vec3 t4 = t2*t2; + + // Calculate the gradients for the three corners + vec2 g0 = grad2(Pi, rot); + vec2 g1 = grad2(Pi + i1, rot); + vec2 g2 = grad2(Pi + 1.0, rot); + + // Compute noise contributions from each corner + vec3 gv = vec3(dot(g0,v0), dot(g1,v1), dot(g2,v2)); // ramp: g dot v + vec3 n = t4 * gv; // Circular kernel times linear ramp + + // Compute partial derivatives in x and y + vec3 temp = t2 * t * gv; + vec3 gradx = temp * vec3(v0.x, v1.x, v2.x); + vec3 grady = temp * vec3(v0.y, v1.y, v2.y); + grad.x = -8.0 * (gradx.x + gradx.y + gradx.z); + grad.y = -8.0 * (grady.x + grady.y + grady.z); + grad.x += dot(t4, vec3(g0.x, g1.x, g2.x)); + grad.y += dot(t4, vec3(g0.y, g1.y, g2.y)); + grad *= 40.0; + + // Add contributions from the three corners and return + return 40.0 * (n.x + n.y + n.z); +} + +-- Vertex.flow + +#version 120 + +varying vec2 vTexCoord2D; + +void main(void) { + vTexCoord2D = gl_Vertex.xy * 8.0; + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +-- Fragment.flow + +varying vec3 vTexCoord3D; +uniform float time; + +void main(void) { + vec2 g1, g2; + vec2 p = vTexCoord2D; + float n1 = srdnoise(p*0.5, 0.2*time, g1); + float n2 = srdnoise(p*2.0 + g1*0.5, 0.51*time, g2); + float n3 = srdnoise(p*4.0 + g1*0.5 + g2*0.25, 0.77*time, g2); + gl_FragColor = vec4(vec3(0.4, 0.5, 0.6) + vec3(n1+0.75*n2+0.5*n3), 1.0); +} + +-- Noise.spots + +#version 120 + +// Cellular noise ("Worley noise") in 3D in GLSL. +// Copyright (c) Stefan Gustavson 2011-04-19. All rights reserved. +// This code is released under the conditions of the MIT license. +// See LICENSE file for details. + +// Cellular noise, returning F1 and F2 in a vec2. +// Speeded up by using 2x2x2 search window instead of 3x3x3, +// at the expense of some pattern artifacts. +// F2 is often wrong and has sharp discontinuities. +// If you need a good F2, use the slower 3x3x3 version. +vec2 cellular2x2x2(vec3 P) +{ +#define K 0.142857142857 // 1/7 +#define Ko 0.428571428571 // 1/2-K/2 +#define K2 0.020408163265306 // 1/(7*7) +#define Kz 0.166666666667 // 1/6 +#define Kzo 0.416666666667 // 1/2-1/6*2 +#define jitter 0.8 // smaller jitter gives less errors in F2 + vec3 Pi = mod(floor(P), 289.0); + vec3 Pf = fract(P); + vec4 Pfx = Pf.x + vec4(0.0, -1.0, 0.0, -1.0); + vec4 Pfy = Pf.y + vec4(0.0, 0.0, -1.0, -1.0); + vec4 p = permute(Pi.x + vec4(0.0, 1.0, 0.0, 1.0)); + p = permute(p + Pi.y + vec4(0.0, 0.0, 1.0, 1.0)); + vec4 p1 = permute(p + Pi.z); // z+0 + vec4 p2 = permute(p + Pi.z + vec4(1.0)); // z+1 + vec4 ox1 = fract(p1*K) - Ko; + vec4 oy1 = mod(floor(p1*K), 7.0)*K - Ko; + vec4 oz1 = floor(p1*K2)*Kz - Kzo; // p1 < 289 guaranteed + vec4 ox2 = fract(p2*K) - Ko; + vec4 oy2 = mod(floor(p2*K), 7.0)*K - Ko; + vec4 oz2 = floor(p2*K2)*Kz - Kzo; + vec4 dx1 = Pfx + jitter*ox1; + vec4 dy1 = Pfy + jitter*oy1; + vec4 dz1 = Pf.z + jitter*oz1; + vec4 dx2 = Pfx + jitter*ox2; + vec4 dy2 = Pfy + jitter*oy2; + vec4 dz2 = Pf.z - 1.0 + jitter*oz2; + vec4 d1 = dx1 * dx1 + dy1 * dy1 + dz1 * dz1; // z+0 + vec4 d2 = dx2 * dx2 + dy2 * dy2 + dz2 * dz2; // z+1 + + // Sort out the two smallest distances (F1, F2) +#if 1 + // Cheat and sort out only F1 + d1 = min(d1, d2); + d1.xy = min(d1.xy, d1.wz); + d1.x = min(d1.x, d1.y); + return sqrt(d1.xx); +#else + // Do it right and sort out both F1 and F2 + vec4 d = min(d1,d2); // F1 is now in d + d2 = max(d1,d2); // Make sure we keep all candidates for F2 + d.xy = (d.x < d.y) ? d.xy : d.yx; // Swap smallest to d.x + d.xz = (d.x < d.z) ? d.xz : d.zx; + d.xw = (d.x < d.w) ? d.xw : d.wx; // F1 is now in d.x + d.yzw = min(d.yzw, d2.yzw); // F2 now not in d2.yzw + d.y = min(d.y, d.z); // nor in d.z + d.y = min(d.y, d.w); // nor in d.w + d.y = min(d.y, d2.x); // F2 is now in d.y + return sqrt(d.xy); // F1 and F2 +#endif +} + +-- Vertex.spots + +#version 120 + +uniform float time; + +varying vec3 vTexCoord3D; + +void main(void) { + vTexCoord3D = gl_Vertex.xyz * 4.0 - vec3(0.0, 0.0, time); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +-- Fragement.spots + +varying vec3 vTexCoord3D; + +void main(void) { + vec2 F = cellular2x2x2(vTexCoord3D); + float s = fwidth(F.x); + float n1 = smoothstep(0.4-s, 0.4+s, F.x); + float n2 = smoothstep(0.5-s, 0.5+s, F.x); + gl_FragColor = vec4(n1, n2, n2, 1.0); +} + +-- Noise.tile + +// Cellular noise ("Worley noise") in 3D in GLSL. +// Copyright (c) Stefan Gustavson 2011-04-19. All rights reserved. +// This code is released under the conditions of the MIT license. +// See LICENSE file for details. + +// Cellular noise, returning F1 and F2 in a vec2. +// 3x3x3 search region for good F2 everywhere, but a lot +// slower than the 2x2x2 version. +// The code below is a bit scary even to its author, +// but it has at least half decent performance on a +// modern GPU. In any case, it beats any software +// implementation of Worley noise hands down. + +vec2 cellular(vec3 P) +{ +#define K 0.142857142857 // 1/7 +#define Ko 0.428571428571 // 1/2-K/2 +#define K2 0.020408163265306 // 1/(7*7) +#define Kz 0.166666666667 // 1/6 +#define Kzo 0.416666666667 // 1/2-1/6*2 +#define jitter 1.0 // smaller jitter gives more regular pattern + + vec3 Pi = mod(floor(P), 289.0); + vec3 Pf = fract(P) - 0.5; + + vec3 Pfx = Pf.x + vec3(1.0, 0.0, -1.0); + vec3 Pfy = Pf.y + vec3(1.0, 0.0, -1.0); + vec3 Pfz = Pf.z + vec3(1.0, 0.0, -1.0); + + vec3 p = permute(Pi.x + vec3(-1.0, 0.0, 1.0)); + vec3 p1 = permute(p + Pi.y - 1.0); + vec3 p2 = permute(p + Pi.y); + vec3 p3 = permute(p + Pi.y + 1.0); + + vec3 p11 = permute(p1 + Pi.z - 1.0); + vec3 p12 = permute(p1 + Pi.z); + vec3 p13 = permute(p1 + Pi.z + 1.0); + + vec3 p21 = permute(p2 + Pi.z - 1.0); + vec3 p22 = permute(p2 + Pi.z); + vec3 p23 = permute(p2 + Pi.z + 1.0); + + vec3 p31 = permute(p3 + Pi.z - 1.0); + vec3 p32 = permute(p3 + Pi.z); + vec3 p33 = permute(p3 + Pi.z + 1.0); + + vec3 ox11 = fract(p11*K) - Ko; + vec3 oy11 = mod(floor(p11*K), 7.0)*K - Ko; + vec3 oz11 = floor(p11*K2)*Kz - Kzo; // p11 < 289 guaranteed + + vec3 ox12 = fract(p12*K) - Ko; + vec3 oy12 = mod(floor(p12*K), 7.0)*K - Ko; + vec3 oz12 = floor(p12*K2)*Kz - Kzo; + + vec3 ox13 = fract(p13*K) - Ko; + vec3 oy13 = mod(floor(p13*K), 7.0)*K - Ko; + vec3 oz13 = floor(p13*K2)*Kz - Kzo; + + vec3 ox21 = fract(p21*K) - Ko; + vec3 oy21 = mod(floor(p21*K), 7.0)*K - Ko; + vec3 oz21 = floor(p21*K2)*Kz - Kzo; + + vec3 ox22 = fract(p22*K) - Ko; + vec3 oy22 = mod(floor(p22*K), 7.0)*K - Ko; + vec3 oz22 = floor(p22*K2)*Kz - Kzo; + + vec3 ox23 = fract(p23*K) - Ko; + vec3 oy23 = mod(floor(p23*K), 7.0)*K - Ko; + vec3 oz23 = floor(p23*K2)*Kz - Kzo; + + vec3 ox31 = fract(p31*K) - Ko; + vec3 oy31 = mod(floor(p31*K), 7.0)*K - Ko; + vec3 oz31 = floor(p31*K2)*Kz - Kzo; + + vec3 ox32 = fract(p32*K) - Ko; + vec3 oy32 = mod(floor(p32*K), 7.0)*K - Ko; + vec3 oz32 = floor(p32*K2)*Kz - Kzo; + + vec3 ox33 = fract(p33*K) - Ko; + vec3 oy33 = mod(floor(p33*K), 7.0)*K - Ko; + vec3 oz33 = floor(p33*K2)*Kz - Kzo; + + vec3 dx11 = Pfx + jitter*ox11; + vec3 dy11 = Pfy.x + jitter*oy11; + vec3 dz11 = Pfz.x + jitter*oz11; + + vec3 dx12 = Pfx + jitter*ox12; + vec3 dy12 = Pfy.x + jitter*oy12; + vec3 dz12 = Pfz.y + jitter*oz12; + + vec3 dx13 = Pfx + jitter*ox13; + vec3 dy13 = Pfy.x + jitter*oy13; + vec3 dz13 = Pfz.z + jitter*oz13; + + vec3 dx21 = Pfx + jitter*ox21; + vec3 dy21 = Pfy.y + jitter*oy21; + vec3 dz21 = Pfz.x + jitter*oz21; + + vec3 dx22 = Pfx + jitter*ox22; + vec3 dy22 = Pfy.y + jitter*oy22; + vec3 dz22 = Pfz.y + jitter*oz22; + + vec3 dx23 = Pfx + jitter*ox23; + vec3 dy23 = Pfy.y + jitter*oy23; + vec3 dz23 = Pfz.z + jitter*oz23; + + vec3 dx31 = Pfx + jitter*ox31; + vec3 dy31 = Pfy.z + jitter*oy31; + vec3 dz31 = Pfz.x + jitter*oz31; + + vec3 dx32 = Pfx + jitter*ox32; + vec3 dy32 = Pfy.z + jitter*oy32; + vec3 dz32 = Pfz.y + jitter*oz32; + + vec3 dx33 = Pfx + jitter*ox33; + vec3 dy33 = Pfy.z + jitter*oy33; + vec3 dz33 = Pfz.z + jitter*oz33; + + vec3 d11 = dx11 * dx11 + dy11 * dy11 + dz11 * dz11; + vec3 d12 = dx12 * dx12 + dy12 * dy12 + dz12 * dz12; + vec3 d13 = dx13 * dx13 + dy13 * dy13 + dz13 * dz13; + vec3 d21 = dx21 * dx21 + dy21 * dy21 + dz21 * dz21; + vec3 d22 = dx22 * dx22 + dy22 * dy22 + dz22 * dz22; + vec3 d23 = dx23 * dx23 + dy23 * dy23 + dz23 * dz23; + vec3 d31 = dx31 * dx31 + dy31 * dy31 + dz31 * dz31; + vec3 d32 = dx32 * dx32 + dy32 * dy32 + dz32 * dz32; + vec3 d33 = dx33 * dx33 + dy33 * dy33 + dz33 * dz33; + + // Sort out the two smallest distances (F1, F2) +#if 0 + // Cheat and sort out only F1 + vec3 d1 = min(min(d11,d12), d13); + vec3 d2 = min(min(d21,d22), d23); + vec3 d3 = min(min(d31,d32), d33); + vec3 d = min(min(d1,d2), d3); + d.x = min(min(d.x,d.y),d.z); + return sqrt(d.xx); // F1 duplicated, no F2 computed +#else + // Do it right and sort out both F1 and F2 + vec3 d1a = min(d11, d12); + d12 = max(d11, d12); + d11 = min(d1a, d13); // Smallest now not in d12 or d13 + d13 = max(d1a, d13); + d12 = min(d12, d13); // 2nd smallest now not in d13 + vec3 d2a = min(d21, d22); + d22 = max(d21, d22); + d21 = min(d2a, d23); // Smallest now not in d22 or d23 + d23 = max(d2a, d23); + d22 = min(d22, d23); // 2nd smallest now not in d23 + vec3 d3a = min(d31, d32); + d32 = max(d31, d32); + d31 = min(d3a, d33); // Smallest now not in d32 or d33 + d33 = max(d3a, d33); + d32 = min(d32, d33); // 2nd smallest now not in d33 + vec3 da = min(d11, d21); + d21 = max(d11, d21); + d11 = min(da, d31); // Smallest now in d11 + d31 = max(da, d31); // 2nd smallest now not in d31 + d11.xy = (d11.x < d11.y) ? d11.xy : d11.yx; + d11.xz = (d11.x < d11.z) ? d11.xz : d11.zx; // d11.x now smallest + d12 = min(d12, d21); // 2nd smallest now not in d21 + d12 = min(d12, d22); // nor in d22 + d12 = min(d12, d31); // nor in d31 + d12 = min(d12, d32); // nor in d32 + d11.yz = min(d11.yz,d12.xy); // nor in d12.yz + d11.y = min(d11.y,d12.z); // Only two more to go + d11.y = min(d11.y,d11.z); // Done! (Phew!) + return sqrt(d11.xy); // F1, F2 +#endif +} + +-- Vertex.tile + +#version 120 + +uniform float time; + +varying vec3 vTexCoord3D; + +void main(void) { + vTexCoord3D = gl_Vertex.xyz * 4.0 + + 0.2 * vec3(snoise(gl_Vertex.xyz + vec3(0.0, 0.0, time)), + snoise(gl_Vertex.xyz + vec3(43.0, 17.0, time)), + snoise(gl_Vertex.xyz + vec3(0.0, -43.0, time-17.0))); + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} + +-- Fragement.tile + +#version 120 + +varying vec3 vTexCoord3D; + +void main(void) { + vec2 F = cellular(vTexCoord3D.xyz); + float n = 0.1+F.y-F.x; + gl_FragColor = vec4(n*0.6, n*1.1, n*0.5, 1.0); +} diff --git a/libs/video/renderer/glsl/vid_common_glsl.c b/libs/video/renderer/glsl/vid_common_glsl.c index d684fd4ff..3fb0b9707 100644 --- a/libs/video/renderer/glsl/vid_common_glsl.c +++ b/libs/video/renderer/glsl/vid_common_glsl.c @@ -58,6 +58,11 @@ static const char quakeforge_effect[] = #include "quakeforge.slc" +"--" // ensure the last block of the previous file doesn't merge with + // the first block of the next file +// Include Stefan Gustavson's noise functions in the QuakeForge shader +// effect "file". +#include "sgustavson.slc" ; int glsl_palette; From 83aa5759a2954072af7d9c787624266d8dbd25b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 29 Jan 2014 15:33:30 +0900 Subject: [PATCH 10/31] Split up the trail fragment shader. The barycentric shader is generally useful for debugging. --- libs/video/renderer/glsl/glsl_particles.c | 13 ++++++++----- libs/video/renderer/glsl/quakeforge.glsl | 17 +++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 6107a5fd9..b9fab5a60 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -115,7 +115,7 @@ static const char *particle_trail_vert_effects[] = static const char *particle_trail_frag_effects[] = { - "QuakeForge.Fragment.particle.trail", + "QuakeForge.Fragment.barycentric", 0 }; @@ -1815,7 +1815,8 @@ draw_trails (void) qfeglEnableVertexAttribArray (trail.last.location); qfeglEnableVertexAttribArray (trail.current.location); qfeglEnableVertexAttribArray (trail.next.location); - qfeglEnableVertexAttribArray (trail.barycentric.location); + if (trail.barycentric.location >= 0) + qfeglEnableVertexAttribArray (trail.barycentric.location); qfeglEnableVertexAttribArray (trail.texoff.location); qfeglUniformMatrix4fv (trail.proj.location, 1, false, glsl_projection); @@ -1830,8 +1831,9 @@ draw_trails (void) 0, sizeof (trailvtx_t), &verts[2].vertex); qfeglVertexAttribPointer (trail.next.location, 4, GL_FLOAT, 0, sizeof (trailvtx_t), &verts[4].vertex); - qfeglVertexAttribPointer (trail.barycentric.location, 3, GL_FLOAT, - 0, sizeof (trailvtx_t), &verts[2].bary); + 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); @@ -1848,7 +1850,8 @@ draw_trails (void) qfeglDisableVertexAttribArray (trail.last.location); qfeglDisableVertexAttribArray (trail.current.location); qfeglDisableVertexAttribArray (trail.next.location); - qfeglDisableVertexAttribArray (trail.barycentric.location); + if (trail.barycentric.location >= 0) + qfeglDisableVertexAttribArray (trail.barycentric.location); qfeglDisableVertexAttribArray (trail.texoff.location); expire_trails (); diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index f214cfd02..80ff0cf4e 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -590,7 +590,7 @@ uniform vec2 viewport; uniform float width; varying vec2 texcoord; -varying vec3 vBC; +varying vec3 vbarycentric; vec4 transform (vec3 coord) @@ -635,7 +635,7 @@ main (void) float off = current.w; texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); - vBC = barycentric; + vbarycentric = barycentric; t = sLast - sCurrent; n1 = vec2 (0.0); @@ -666,20 +666,22 @@ main (void) uniform sampler2D smoke; varying vec2 texcoord; -varying vec3 vBC; -#if 0 void main (void) { gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); } -#else + +-- Fragment.barycentric + +varying vec3 vbarycentric; + float edgeFactor (void) { - vec3 d = fwidth (vBC); - vec3 a3 = smoothstep (vec3 (0.0), d * 1.5, vBC); + vec3 d = fwidth (vbarycentric); + vec3 a3 = smoothstep (vec3 (0.0), d * 1.5, vbarycentric); return min (min (a3.x, a3.y), a3.z); } @@ -688,4 +690,3 @@ main (void) { gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); } -#endif From bb5f5dd334a2b6a711c89114173aac7d93a56e22 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 29 Jan 2014 15:36:16 +0900 Subject: [PATCH 11/31] Correct the spelling of Fragment. --- libs/video/renderer/glsl/sgustavson.glsl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/video/renderer/glsl/sgustavson.glsl b/libs/video/renderer/glsl/sgustavson.glsl index 59aa9f5f2..de7d86553 100644 --- a/libs/video/renderer/glsl/sgustavson.glsl +++ b/libs/video/renderer/glsl/sgustavson.glsl @@ -187,7 +187,7 @@ void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } --- Fragement.flame +-- Fragment.flame varying vec3 vTexCoord3D; void main( void ) @@ -394,7 +394,7 @@ void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } --- Fragement.spots +-- Fragment.spots varying vec3 vTexCoord3D; @@ -595,7 +595,7 @@ void main(void) { gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; } --- Fragement.tile +-- Fragment.tile #version 120 From 0057970e3cbeaef9690ab317067267b635807f42 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 31 Jan 2014 10:13:56 +0900 Subject: [PATCH 12/31] Build the chunk chain correctly. Losing all the middle chunks wasn't nice. --- libs/util/segtext.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/util/segtext.c b/libs/util/segtext.c index 742983be1..851dff94f 100644 --- a/libs/util/segtext.c +++ b/libs/util/segtext.c @@ -151,10 +151,9 @@ Segtext_new (const char *source_string) (*chunk)->text = src; (*chunk)->start_line = line; - chunk = &(*chunk)->next; - while ((src = next_chunk (src, &line))) { *src++ = 0; // terminate the previous chunk + chunk = &(*chunk)->next; *chunk = new_chunk (); (*chunk)->tag = find_tag (src); src = next_line (src, &line); From bcb1049f885a0bb95f4bb644e6d5d70ce5cf3f5f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 31 Jan 2014 10:40:44 +0900 Subject: [PATCH 13/31] Convert particle physics to a scripted system. The script format is the same as the console command-line, so no new format :). The scripts are compiled to byte code and cached. They are referenced by name (eg, "pt_fire"), though the names are likely to change. It seems to work quite well and should prove to be a good basis for scripting particle effects in general. --- include/QF/plugin/vid_render.h | 15 +- include/QF/render.h | 19 - include/d_iface.h | 14 +- include/r_dynamic.h | 8 +- libs/video/renderer/Makefile.am | 11 + libs/video/renderer/gl/gl_dyn_part.c | 106 ++--- libs/video/renderer/glsl/glsl_particles.c | 120 +++--- libs/video/renderer/particles.part | 83 ++++ libs/video/renderer/r_part.c | 468 ++++++++++++++++------ libs/video/renderer/sw/sw_rmain.c | 1 + libs/video/renderer/sw/sw_rpart.c | 66 ++- libs/video/renderer/sw32/sw32_rmain.c | 1 + libs/video/renderer/sw32/sw32_rpart.c | 66 ++- libs/video/renderer/vid_render_gl.c | 2 + libs/video/renderer/vid_render_glsl.c | 2 + libs/video/renderer/vid_render_sw.c | 2 + libs/video/renderer/vid_render_sw32.c | 2 + qw/source/cl_ents.c | 4 +- 18 files changed, 649 insertions(+), 341 deletions(-) create mode 100644 libs/video/renderer/particles.part diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 04ee6e33b..1c20ea8f0 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -36,6 +36,7 @@ struct plitem_s; struct cvar_s; struct skin_s; +struct particle_s; /* All video plugins must export these functions @@ -70,13 +71,13 @@ typedef struct vid_particle_funcs_s { void (*R_DarkFieldParticles) (struct entity_s *ent); void (*R_EntityParticles) (struct entity_s *ent); - void (*R_Particle_New) (ptype_t type, int texnum, const vec3_t org, + 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) (ptype_t 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_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); } vid_particle_funcs_t; typedef struct vid_model_funcs_s { @@ -160,6 +161,10 @@ typedef struct vid_render_funcs_s { void (*R_DecayLights) (double frametime); void (*R_ViewChanged) (float aspect); + qboolean (*R_CompileParticlePhysics) (const char *name, const char *code); + qboolean (*R_AddParticlePhysicsFunction) + (const char *name, qboolean (*func) (struct particle_s *, void *), + void *data); void (*R_ClearParticles) (void); void (*R_InitParticles) (void); void (*SCR_ScreenShot_f) (void); diff --git a/include/QF/render.h b/include/QF/render.h index 55514632b..3ff4af2ac 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -33,25 +33,6 @@ #include "QF/qdefs.h" // FIXME #include "QF/vid.h" -typedef enum { - pt_static, - pt_grav, - pt_slowgrav, - pt_fire, - pt_explode, - pt_explode2, - pt_blob, - pt_blob2, - pt_smoke, - pt_smokecloud, - pt_bloodcloud, - pt_fadespark, - pt_fadespark2, - pt_fallfade, - pt_fallfadespark, - pt_flame -} ptype_t; - extern struct vid_render_funcs_s *r_funcs; extern struct vid_render_data_s *r_data; diff --git a/include/d_iface.h b/include/d_iface.h index f7d6a72a2..df6336a40 100644 --- a/include/d_iface.h +++ b/include/d_iface.h @@ -63,9 +63,16 @@ typedef enum { } ptextype_t; typedef struct particle_s particle_t; -typedef void (*pt_phys_func)(particle_t *); -pt_phys_func R_ParticlePhysics (ptype_t type); +void R_LoadParticles (void); +qboolean R_CompileParticlePhysics (const char *name, const char *code); +void R_RunParticlePhysics (particle_t *part); +const union pt_phys_op_s *R_ParticlePhysics (const char *type); +qboolean R_AddParticlePhysicsFunction (const char *name, + qboolean (*func) (struct particle_s *, + void *), + void *data); +extern const char particle_types[]; // !!! if this is changed, it must be changed in d_ifacea.h too !!! struct particle_s @@ -78,10 +85,9 @@ struct particle_s float scale; // drivers never touch the following fields vec3_t vel; - ptype_t type; float die; float ramp; - pt_phys_func phys; + const union pt_phys_op_s *physics; particle_t *next; }; diff --git a/include/r_dynamic.h b/include/r_dynamic.h index 1dd54fc11..0adeb4839 100644 --- a/include/r_dynamic.h +++ b/include/r_dynamic.h @@ -49,10 +49,10 @@ void R_PushDlights (const vec3_t entorigin); struct cvar_s; void R_MaxDlightsCheck (struct cvar_s *var); void R_Particles_Init_Cvars (void); -void R_Particle_New (ptype_t 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 (ptype_t type, int texnum, const vec3_t org, +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); diff --git a/libs/video/renderer/Makefile.am b/libs/video/renderer/Makefile.am index 2c234fe33..7f7119c14 100644 --- a/libs/video/renderer/Makefile.am +++ b/libs/video/renderer/Makefile.am @@ -10,9 +10,17 @@ plugin_ldflags= @plugin_ldflags@ -avoid-version -module -rpath $(plugindir) plugin_libadd= @plugin_libadd@ EXEEXT= +particles_src= particles.part +particles_gen= particles.pc + +SUFFICES=.part .pc +.part.pc: + sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $< > $@ + #lib_LTLIBRARIES= @VID_REND_TARGETS@ plugin_LTLIBRARIES= @vid_render_plugins@ noinst_LTLIBRARIES= libQFrenderer.la @vid_render_static_plugins@ +BUILT_SOURCES= $(particles_gen) EXTRA_LTLIBRARIES= \ vid_render_sw.la vid_render_sw32.la \ @@ -63,3 +71,6 @@ vid_render_sw32_la_LDFLAGS= $(plugin_ldflags) vid_render_sw32_la_LIBADD= $(sw32_libs) vid_render_sw32_la_DEPENDENCIES=$(sw32_libs) vid_render_sw32_la_SOURCES= $(common_sources) vid_render_sw32.c + +EXTRA_DIST = $(particles_src) +CLEANFILES= *.pc diff --git a/libs/video/renderer/gl/gl_dyn_part.c b/libs/video/renderer/gl/gl_dyn_part.c index 77428573b..f249624b6 100644 --- a/libs/video/renderer/gl/gl_dyn_part.c +++ b/libs/video/renderer/gl/gl_dyn_part.c @@ -70,7 +70,7 @@ static varray_t2f_c4ub_v3f_t *particleVertexArray; static mtstate_t mt; // private PRNG state inline static void -particle_new (ptype_t type, int texnum, const vec3_t org, float scale, +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) { particle_t *part; @@ -91,10 +91,9 @@ particle_new (ptype_t type, int texnum, const vec3_t org, float scale, part->scale = scale; part->alpha = alpha; VectorCopy (vel, part->vel); - part->type = type; part->die = die; part->ramp = ramp; - part->phys = R_ParticlePhysics (type); + part->physics = R_ParticlePhysics (type); } /* @@ -104,7 +103,8 @@ particle_new (ptype_t type, int texnum, const vec3_t org, float scale, going to bother using this function. */ inline static void -particle_new_random (ptype_t type, int texnum, const vec3_t org, int org_fuzz, +particle_new_random (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) { @@ -153,6 +153,8 @@ gl_R_InitParticles (void) { int i; + R_LoadParticles (); + mtwist_seed (&mt, 0xdeadbeef); if (r_maxparticles && r_init) { @@ -234,7 +236,7 @@ gl_R_ReadPointFile_f (void) Sys_MaskPrintf (SYS_DEV, "Not enough free particles\n"); break; } else { - particle_new (pt_static, part_tex_dot, org, 1.5, vec3_origin, + particle_new ("pt_static", part_tex_dot, org, 1.5, vec3_origin, 99999, (-c) & 15, 1.0, 0.0); } } @@ -248,7 +250,7 @@ R_ParticleExplosion_QF (const vec3_t org) // R_NewExplosion (org); if (numparticles >= r_maxparticles) return; - particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8, + particle_new_random ("pt_smokecloud", part_tex_smoke, org, 4, 30, 8, vr_data.realtime + 5.0, (mtwist_rand (&mt) & 7) + 8, 0.5 + qfrandom (0.25), 0.0); } @@ -264,7 +266,7 @@ R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) j = r_maxparticles - numparticles; for (i = 0; i < j; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 16, 2, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 16, 2, 256, vr_data.realtime + 0.3, colorStart + (i % colorLength), 1.0, 0.0); } @@ -282,12 +284,12 @@ R_BlobExplosion_QF (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 12, 2, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 12, 2, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05, 66 + i % 6, 1.0, 0.0); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_blob2, part_tex_dot, org, 12, 2, 256, + particle_new_random ("pt_blob2", part_tex_dot, org, 12, 2, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05, 150 + i % 6, 1.0, 0.0); } @@ -298,7 +300,7 @@ R_RunSparkEffect_QF (const vec3_t org, int count, int ofuzz) { if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, ofuzz * 0.08, + particle_new ("pt_smokecloud", part_tex_smoke, org, ofuzz * 0.08, vec3_origin, vr_data.realtime + 9, 12 + (mtwist_rand (&mt) & 3), 0.25 + qfrandom (0.125), 0.0); @@ -312,7 +314,7 @@ R_RunSparkEffect_QF (const vec3_t org, int count, int ofuzz) while (count--) { int color = mtwist_rand (&mt) & 7; - particle_new_random (pt_fallfadespark, part_tex_dot, org, orgfuzz, + particle_new_random ("pt_fallfadespark", part_tex_dot, org, orgfuzz, 0.7, 96, vr_data.realtime + 5.0, ramp1[color], 1.0, color); } @@ -325,7 +327,7 @@ R_BloodPuff_QF (const vec3_t org, int count) if (numparticles >= r_maxparticles) return; - particle_new (pt_bloodcloud, part_tex_smoke, org, count / 5, vec3_origin, + particle_new ("pt_bloodcloud", part_tex_smoke, org, count / 5, vec3_origin, vr_data.realtime + 99.0, 70 + (mtwist_rand (&mt) & 3), 0.5, 0.0); } @@ -353,14 +355,14 @@ R_LightningBloodEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 3.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 3.0, vec3_origin, vr_data.realtime + 9.0, 12 + (mtwist_rand (&mt) & 3), 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_spark, org, 12, 2.0, 128, + particle_new_random ("pt_fallfade", part_tex_spark, org, 12, 2.0, 128, vr_data.realtime + 5.0, 244 + (count % 3), 1.0, 0.0); } @@ -388,7 +390,7 @@ R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, porg[1] = org[1] + scale * (((rnd >> 7) & 15) - 7.5); porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 7.5); // Note that ParseParticleEffect handles (dir * 15) - particle_new (pt_grav, part_tex_dot, porg, 1.5, dir, + particle_new ("pt_grav", part_tex_dot, porg, 1.5, dir, vr_data.realtime + 0.1 * (i % 5), (color & ~7) + (rnd & 7), 1.0, 0.0); } @@ -413,13 +415,13 @@ R_KnightSpikeEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 1.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 1.0, vec3_origin, vr_data.realtime + 9.0, 234, 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_dot, org, 6, 0.7, 96, + particle_new_random ("pt_fallfade", part_tex_dot, org, 6, 0.7, 96, vr_data.realtime + 5.0, 234, 1.0, 0.0); } @@ -430,13 +432,13 @@ R_WizSpikeEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 2.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 2.0, vec3_origin, vr_data.realtime + 9.0, 63, 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_dot, org, 12, 0.7, 96, + particle_new_random ("pt_fallfade", part_tex_dot, org, 12, 0.7, 96, vr_data.realtime + 5.0, 63, 1.0, 0.0); } @@ -469,7 +471,7 @@ R_LavaSplash_QF (const vec3_t org) rnd = mtwist_rand (&mt); vel = 50.0 + 0.5 * (float) (rnd & 127); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 3, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 3, pvel, vr_data.realtime + 2.0 + ((rnd >> 7) & 31) * 0.02, 224 + ((rnd >> 12) & 7), 0.75, 0.0); } @@ -507,7 +509,7 @@ R_TeleportSplash_QF (const vec3_t org) vel = 50 + ((rnd >> 6) & 63); VectorScale (pdir, vel, pvel); - particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel, + particle_new ("pt_grav", part_tex_spark, porg, 0.6, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01), (7 + ((rnd >> 12) & 7)), 1.0, 0.0); } @@ -536,7 +538,7 @@ R_RocketTrail_QF (entity_t *ent) dist = (pscale + pscalenext) * 3.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, 12 + (mtwist_rand (&mt) & 3), @@ -570,7 +572,7 @@ R_GrenadeTrail_QF (entity_t *ent) dist = (pscale + pscalenext) * 2.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, 1 + (mtwist_rand (&mt) & 3), @@ -612,7 +614,7 @@ R_BloodTrail_QF (entity_t *ent) percent = len * origlen; pvel[2] -= percent * 40.0; - particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel, + particle_new ("pt_grav", part_tex_smoke, porg, pscale, pvel, vr_data.realtime + 2.0 - percent * 2.0, 68 + (mtwist_rand (&mt) & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -652,7 +654,7 @@ R_SlightBloodTrail_QF (entity_t *ent) percent = len * origlen; pvel[2] -= percent * 40; - particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel, + particle_new ("pt_grav", part_tex_smoke, porg, pscale, pvel, vr_data.realtime + 1.5 - percent * 1.5, 68 + (mtwist_rand (&mt) & 3), 0.75, 0.0); if (numparticles >= r_maxparticles) @@ -693,7 +695,7 @@ R_WizTrail_QF (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_flame, part_tex_smoke, old_origin, + particle_new ("pt_flame", part_tex_smoke, old_origin, 2.0 + qfrandom (1.0) - percent * 2.0, pvel, vr_data.realtime + 0.5 - percent * 0.5, 52 + (mtwist_rand (&mt) & 4), 1.0 - percent * 0.125, 0.0); @@ -734,7 +736,7 @@ R_FlameTrail_QF (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_flame, part_tex_smoke, old_origin, + particle_new ("pt_flame", part_tex_smoke, old_origin, 2.0 + qfrandom (1.0) - percent * 2.0, pvel, vr_data.realtime + 0.5 - percent * 0.5, 234, 1.0 - percent * 0.125, 0.0); @@ -768,7 +770,7 @@ R_VoorTrail_QF (entity_t *ent) for (j = 0; j < 3; j++) porg[j] = old_origin[j] + qfrandom (16.0) - 8.0; - particle_new (pt_static, part_tex_dot, porg, 1.0 + qfrandom (1.0), + particle_new ("pt_static", part_tex_dot, porg, 1.0 + qfrandom (1.0), vec3_origin, vr_data.realtime + 0.3 - percent * 0.3, 9 * 16 + 8 + (mtwist_rand (&mt) & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -803,7 +805,7 @@ R_GlowTrail_QF (entity_t *ent, int glow_color) org[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_smoke, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_smoke", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0 - percent * 0.2, glow_color, 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -821,7 +823,7 @@ R_ParticleExplosion_EE (const vec3_t org) */ if (numparticles >= r_maxparticles) return; - particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8, + particle_new_random ("pt_smokecloud", part_tex_smoke, org, 4, 30, 8, vr_data.realtime + 5.0, mtwist_rand (&mt) & 255, 0.5 + qfrandom (0.25), 0.0); } @@ -855,7 +857,7 @@ R_TeleportSplash_EE (const vec3_t org) VectorNormalize (dir); vel = 50 + ((rnd >> 6) & 63); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel, + particle_new ("pt_grav", part_tex_spark, porg, 0.6, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01), qfrandom (1.0), 1.0, 0.0); } @@ -884,7 +886,7 @@ R_RocketTrail_EE (entity_t *ent) dist = (pscale + pscalenext) * 3.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, mtwist_rand (&mt) & 255, @@ -919,7 +921,7 @@ R_GrenadeTrail_EE (entity_t *ent) dist = (pscale + pscalenext) * 2.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, mtwist_rand (&mt) & 255, @@ -945,11 +947,11 @@ R_ParticleExplosion_ID (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_explode, part_tex_dot, org, 16, 1.0, 256, + particle_new_random ("pt_explode", part_tex_dot, org, 16, 1.0, 256, vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_explode2, part_tex_dot, org, 16, 1.0, 256, + particle_new_random ("pt_explode2", part_tex_dot, org, 16, 1.0, 256, vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3); } } @@ -966,12 +968,12 @@ R_BlobExplosion_ID (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 12, 1.0, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 12, 1.0, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05, 66 + i % 6, 1.0, 0.0); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_blob2, part_tex_dot, org, 12, 1.0, 256, + particle_new_random ("pt_blob2", part_tex_dot, org, 12, 1.0, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05, 150 + i % 6, 1.0, 0.0); } @@ -1006,7 +1008,7 @@ R_RunParticleEffect_ID (const vec3_t org, const vec3_t dir, int color, porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 8); // Note that ParseParticleEffect handles (dir * 15) - particle_new (pt_grav, part_tex_dot, porg, 1.0, dir, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, dir, vr_data.realtime + 0.1 * (i % 5), (color & ~7) + (rnd & 7), 1.0, 0.0); } @@ -1083,7 +1085,7 @@ R_LavaSplash_ID (const vec3_t org) rnd = mtwist_rand (&mt); vel = 50 + (rnd & 63); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, pvel, vr_data.realtime + 2 + ((rnd >> 7) & 31) * 0.02, 224 + ((rnd >> 12) & 7), 1.0, 0.0); } @@ -1121,7 +1123,7 @@ R_TeleportSplash_ID (const vec3_t org) vel = 50 + ((rnd >> 6) & 63); VectorScale (pdir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02), (7 + ((rnd >> 12) & 7)), 1.0, 0.0); } @@ -1160,7 +1162,7 @@ R_DarkFieldParticles_ID (entity_t *ent) VectorNormalize (dir); vel = 50 + ((rnd >> 9) & 63); VectorScale (dir, vel, pvel); - particle_new (pt_slowgrav, part_tex_dot, porg, 1.5, pvel, + particle_new ("pt_slowgrav", part_tex_dot, porg, 1.5, pvel, (vr_data.realtime + 0.2 + (rnd & 7) * 0.02), (150 + mtwist_rand (&mt) % 6), 1.0, 0.0); } @@ -1215,7 +1217,7 @@ R_EntityParticles_ID (entity_t *ent) forward[1] * beamlength; porg[2] = ent->origin[2] + r_avertexnormals[i][2] * dist + forward[2] * beamlength; - particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_explode", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); } } @@ -1243,7 +1245,7 @@ R_RocketTrail_ID (entity_t *ent) org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; ramp = rnd & 3; - particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_fire", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp); if (numparticles >= r_maxparticles) break; @@ -1275,7 +1277,7 @@ R_GrenadeTrail_ID (entity_t *ent) org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; ramp = (rnd & 3) + 2; - particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_fire", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp); if (numparticles >= r_maxparticles) break; @@ -1306,7 +1308,7 @@ R_BloodTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 2.0, 67 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) break; @@ -1337,7 +1339,7 @@ R_SlightBloodTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 1.5, 67 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) break; @@ -1373,7 +1375,7 @@ R_WizTrail_ID (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel, + particle_new ("pt_static", part_tex_dot, old_origin, 1.0, pvel, vr_data.realtime + 0.5, 52 + ((tracercount & 4) << 1), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1410,7 +1412,7 @@ R_FlameTrail_ID (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel, + particle_new ("pt_static", part_tex_dot, old_origin, 1.0, pvel, vr_data.realtime + 0.5, 230 + ((tracercount & 4) << 1), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1442,7 +1444,7 @@ R_VoorTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 7) & 15) - 7.5; porg[2] = old_origin[2] + ((rnd >> 11) & 15) - 7.5; - particle_new (pt_static, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_static", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.3, 9 * 16 + 8 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1550,7 +1552,7 @@ gl_R_DrawParticles (void) } } - part->phys (part); + R_RunParticlePhysics (part); // LordHavoc: immediate removal of unnecessary particles (must be done // to ensure compactor below operates properly in all cases) @@ -1777,7 +1779,7 @@ gl_R_Particles_Init_Cvars (void) } void -gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, +gl_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) { @@ -1787,7 +1789,7 @@ gl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, } void -gl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, +gl_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) { diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index b9fab5a60..e681aa01f 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -228,7 +228,7 @@ free_point (particle_t *point) } inline static void -particle_new (ptype_t type, int texnum, const vec3_t org, float scale, +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) { particle_t *part; @@ -249,10 +249,9 @@ particle_new (ptype_t type, int texnum, const vec3_t org, float scale, part->scale = scale; part->alpha = alpha; VectorCopy (vel, part->vel); - part->type = type; part->die = die; part->ramp = ramp; - part->phys = R_ParticlePhysics (type); + part->physics = R_ParticlePhysics (type); } /* @@ -262,9 +261,9 @@ particle_new (ptype_t type, int texnum, const vec3_t org, float scale, going to bother using this function. */ inline static void -particle_new_random (ptype_t type, int texnum, const vec3_t org, int org_fuzz, - float scale, int vel_fuzz, float die, int color, - float alpha, float ramp) +particle_new_random (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) { float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; int rnd; @@ -317,6 +316,8 @@ glsl_R_InitParticles (void) byte data[64][64][2]; tex_t *tex; + R_LoadParticles (); + mtwist_seed (&mt, 0xdeadbeef); qfeglEnable (GL_VERTEX_PROGRAM_POINT_SIZE); @@ -447,7 +448,7 @@ glsl_R_ReadPointFile_f (void) Sys_MaskPrintf (SYS_DEV, "Not enough free particles\n"); break; } else { - particle_new (pt_static, part_tex_dot, org, 1.5, vec3_origin, + particle_new ("pt_static", part_tex_dot, org, 1.5, vec3_origin, 99999, (-c) & 15, 1.0, 0.0); } } @@ -461,7 +462,7 @@ R_ParticleExplosion_QF (const vec3_t org) // R_NewExplosion (org); if (numparticles >= r_maxparticles) return; - particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8, + particle_new_random ("pt_smokecloud", part_tex_smoke, org, 4, 30, 8, vr_data.realtime + 5.0, (mtwist_rand (&mt) & 7) + 8, 0.5 + qfrandom (0.25), 0.0); } @@ -477,7 +478,7 @@ R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) j = r_maxparticles - numparticles; for (i = 0; i < j; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 16, 2, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 16, 2, 256, vr_data.realtime + 0.3, colorStart + (i % colorLength), 1.0, 0.0); } @@ -495,12 +496,12 @@ R_BlobExplosion_QF (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 12, 2, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 12, 2, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05, 66 + i % 6, 1.0, 0.0); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_blob2, part_tex_dot, org, 12, 2, 256, + particle_new_random ("pt_blob2", part_tex_dot, org, 12, 2, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 7) * 0.05, 150 + i % 6, 1.0, 0.0); } @@ -511,7 +512,7 @@ R_RunSparkEffect_QF (const vec3_t org, int count, int ofuzz) { if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, ofuzz * 0.08, + particle_new ("pt_smokecloud", part_tex_smoke, org, ofuzz * 0.08, vec3_origin, vr_data.realtime + 9, 12 + (mtwist_rand (&mt) & 3), 0.25 + qfrandom (0.125), 0.0); @@ -525,7 +526,7 @@ R_RunSparkEffect_QF (const vec3_t org, int count, int ofuzz) while (count--) { int color = mtwist_rand (&mt) & 7; - particle_new_random (pt_fallfadespark, part_tex_dot, org, orgfuzz, + particle_new_random ("pt_fallfadespark", part_tex_dot, org, orgfuzz, 0.7, 96, vr_data.realtime + 5.0, ramp1[color], 1.0, color); } @@ -538,7 +539,7 @@ R_BloodPuff_QF (const vec3_t org, int count) if (numparticles >= r_maxparticles) return; - particle_new (pt_bloodcloud, part_tex_smoke, org, count / 5, vec3_origin, + particle_new ("pt_bloodcloud", part_tex_smoke, org, count / 5, vec3_origin, vr_data.realtime + 99.0, 70 + (mtwist_rand (&mt) & 3), 0.5, 0.0); } @@ -566,14 +567,14 @@ R_LightningBloodEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 3.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 3.0, vec3_origin, vr_data.realtime + 9.0, 12 + (mtwist_rand (&mt) & 3), 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_spark, org, 12, 2.0, 128, + particle_new_random ("pt_fallfade", part_tex_spark, org, 12, 2.0, 128, vr_data.realtime + 5.0, 244 + (count % 3), 1.0, 0.0); } @@ -601,7 +602,7 @@ R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, porg[1] = org[1] + scale * (((rnd >> 7) & 15) - 7.5); porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 7.5); // Note that ParseParticleEffect handles (dir * 15) - particle_new (pt_grav, part_tex_dot, porg, 1.5, dir, + particle_new ("pt_grav", part_tex_dot, porg, 1.5, dir, vr_data.realtime + 0.1 * (i % 5), (color & ~7) + (rnd & 7), 1.0, 0.0); } @@ -626,13 +627,13 @@ R_KnightSpikeEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 1.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 1.0, vec3_origin, vr_data.realtime + 9.0, 234, 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_dot, org, 6, 0.7, 96, + particle_new_random ("pt_fallfade", part_tex_dot, org, 6, 0.7, 96, vr_data.realtime + 5.0, 234, 1.0, 0.0); } @@ -643,13 +644,13 @@ R_WizSpikeEffect_QF (const vec3_t org) if (numparticles >= r_maxparticles) return; - particle_new (pt_smokecloud, part_tex_smoke, org, 2.0, vec3_origin, + particle_new ("pt_smokecloud", part_tex_smoke, org, 2.0, vec3_origin, vr_data.realtime + 9.0, 63, 0.25 + qfrandom (0.125), 0.0); if (numparticles + count >= r_maxparticles) count = r_maxparticles - numparticles; while (count--) - particle_new_random (pt_fallfade, part_tex_dot, org, 12, 0.7, 96, + particle_new_random ("pt_fallfade", part_tex_dot, org, 12, 0.7, 96, vr_data.realtime + 5.0, 63, 1.0, 0.0); } @@ -682,7 +683,7 @@ R_LavaSplash_QF (const vec3_t org) rnd = mtwist_rand (&mt); vel = 50.0 + 0.5 * (float) (rnd & 127); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 3, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 3, pvel, vr_data.realtime + 2.0 + ((rnd >> 7) & 31) * 0.02, 224 + ((rnd >> 12) & 7), 0.75, 0.0); } @@ -720,7 +721,7 @@ R_TeleportSplash_QF (const vec3_t org) vel = 50 + ((rnd >> 6) & 63); VectorScale (pdir, vel, pvel); - particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel, + particle_new ("pt_grav", part_tex_spark, porg, 0.6, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01), (7 + ((rnd >> 12) & 7)), 1.0, 0.0); } @@ -764,10 +765,9 @@ R_RocketTrail_trail (entity_t *ent) point->scale = pscale + percent * 4.0; point->alpha = 0.5 + qfrandom (0.125) - percent * 0.40; VectorCopy (vec3_origin, point->vel); - point->type = pt_smoke; point->die = vr_data.realtime + 2.0 - percent * 2.0; point->ramp = 0.0; - point->phys = R_ParticlePhysics (point->type); + point->physics = R_ParticlePhysics ("pt_fire"); *ent->trail->head = point; ent->trail->head = &point->next; @@ -800,7 +800,7 @@ R_RocketTrail_QF (entity_t *ent) dist = (pscale + pscalenext) * 3.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, 12 + (mtwist_rand (&mt) & 3), @@ -834,7 +834,7 @@ R_GrenadeTrail_QF (entity_t *ent) dist = (pscale + pscalenext) * 2.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, 1 + (mtwist_rand (&mt) & 3), @@ -876,7 +876,7 @@ R_BloodTrail_QF (entity_t *ent) percent = len * origlen; pvel[2] -= percent * 40.0; - particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel, + particle_new ("pt_grav", part_tex_smoke, porg, pscale, pvel, vr_data.realtime + 2.0 - percent * 2.0, 68 + (mtwist_rand (&mt) & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -916,7 +916,7 @@ R_SlightBloodTrail_QF (entity_t *ent) percent = len * origlen; pvel[2] -= percent * 40; - particle_new (pt_grav, part_tex_smoke, porg, pscale, pvel, + particle_new ("pt_grav", part_tex_smoke, porg, pscale, pvel, vr_data.realtime + 1.5 - percent * 1.5, 68 + (mtwist_rand (&mt) & 3), 0.75, 0.0); if (numparticles >= r_maxparticles) @@ -957,7 +957,7 @@ R_WizTrail_QF (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_flame, part_tex_smoke, old_origin, + particle_new ("pt_flame", part_tex_smoke, old_origin, 2.0 + qfrandom (1.0) - percent * 2.0, pvel, vr_data.realtime + 0.5 - percent * 0.5, 52 + (mtwist_rand (&mt) & 4), 1.0 - percent * 0.125, 0.0); @@ -998,7 +998,7 @@ R_FlameTrail_QF (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_flame, part_tex_smoke, old_origin, + particle_new ("pt_flame", part_tex_smoke, old_origin, 2.0 + qfrandom (1.0) - percent * 2.0, pvel, vr_data.realtime + 0.5 - percent * 0.5, 234, 1.0 - percent * 0.125, 0.0); @@ -1032,7 +1032,7 @@ R_VoorTrail_QF (entity_t *ent) for (j = 0; j < 3; j++) porg[j] = old_origin[j] + qfrandom (16.0) - 8.0; - particle_new (pt_static, part_tex_dot, porg, 1.0 + qfrandom (1.0), + particle_new ("pt_static", part_tex_dot, porg, 1.0 + qfrandom (1.0), vec3_origin, vr_data.realtime + 0.3 - percent * 0.3, 9 * 16 + 8 + (mtwist_rand (&mt) & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1067,7 +1067,7 @@ R_GlowTrail_QF (entity_t *ent, int glow_color) org[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_smoke, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_smoke", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0 - percent * 0.2, glow_color, 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1085,7 +1085,7 @@ R_ParticleExplosion_EE (const vec3_t org) */ if (numparticles >= r_maxparticles) return; - particle_new_random (pt_smokecloud, part_tex_smoke, org, 4, 30, 8, + particle_new_random ("pt_smokecloud", part_tex_smoke, org, 4, 30, 8, vr_data.realtime + 5.0, mtwist_rand (&mt) & 255, 0.5 + qfrandom (0.25), 0.0); } @@ -1119,7 +1119,7 @@ R_TeleportSplash_EE (const vec3_t org) VectorNormalize (dir); vel = 50 + ((rnd >> 6) & 63); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_spark, porg, 0.6, pvel, + particle_new ("pt_grav", part_tex_spark, porg, 0.6, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 15) * 0.01), qfrandom (1.0), 1.0, 0.0); } @@ -1148,7 +1148,7 @@ R_RocketTrail_EE (entity_t *ent) dist = (pscale + pscalenext) * 3.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, mtwist_rand (&mt) & 255, @@ -1183,7 +1183,7 @@ R_GrenadeTrail_EE (entity_t *ent) dist = (pscale + pscalenext) * 2.0; percent = len * origlen; - particle_new (pt_smoke, part_tex_smoke, old_origin, + particle_new ("pt_smoke", part_tex_smoke, old_origin, pscale + percent * 4.0, vec3_origin, vr_data.realtime + 2.0 - percent * 2.0, mtwist_rand (&mt) & 255, @@ -1209,11 +1209,11 @@ R_ParticleExplosion_ID (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_explode, part_tex_dot, org, 16, 1.0, 256, + particle_new_random ("pt_explode", part_tex_dot, org, 16, 1.0, 256, vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_explode2, part_tex_dot, org, 16, 1.0, 256, + particle_new_random ("pt_explode2", part_tex_dot, org, 16, 1.0, 256, vr_data.realtime + 5.0, ramp1[0], 1.0, i & 3); } } @@ -1230,12 +1230,12 @@ R_BlobExplosion_ID (const vec3_t org) j = r_maxparticles - numparticles; for (i = 0; i < j >> 1; i++) { - particle_new_random (pt_blob, part_tex_dot, org, 12, 1.0, 256, + particle_new_random ("pt_blob", part_tex_dot, org, 12, 1.0, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05, 66 + i % 6, 1.0, 0.0); } for (i = 0; i < j / 2; i++) { - particle_new_random (pt_blob2, part_tex_dot, org, 12, 1.0, 256, + particle_new_random ("pt_blob2", part_tex_dot, org, 12, 1.0, 256, vr_data.realtime + 1.0 + (mtwist_rand (&mt) & 8) * 0.05, 150 + i % 6, 1.0, 0.0); } @@ -1270,7 +1270,7 @@ R_RunParticleEffect_ID (const vec3_t org, const vec3_t dir, int color, porg[2] = org[2] + scale * (((rnd >> 11) & 15) - 8); // Note that ParseParticleEffect handles (dir * 15) - particle_new (pt_grav, part_tex_dot, porg, 1.0, dir, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, dir, vr_data.realtime + 0.1 * (i % 5), (color & ~7) + (rnd & 7), 1.0, 0.0); } @@ -1347,7 +1347,7 @@ R_LavaSplash_ID (const vec3_t org) rnd = mtwist_rand (&mt); vel = 50 + (rnd & 63); VectorScale (dir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, pvel, vr_data.realtime + 2 + ((rnd >> 7) & 31) * 0.02, 224 + ((rnd >> 12) & 7), 1.0, 0.0); } @@ -1385,7 +1385,7 @@ R_TeleportSplash_ID (const vec3_t org) vel = 50 + ((rnd >> 6) & 63); VectorScale (pdir, vel, pvel); - particle_new (pt_grav, part_tex_dot, porg, 1.0, pvel, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, pvel, (vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02), (7 + ((rnd >> 12) & 7)), 1.0, 0.0); } @@ -1424,7 +1424,7 @@ R_DarkFieldParticles_ID (entity_t *ent) VectorNormalize (dir); vel = 50 + ((rnd >> 9) & 63); VectorScale (dir, vel, pvel); - particle_new (pt_slowgrav, part_tex_dot, porg, 1.5, pvel, + particle_new ("pt_slowgrav", part_tex_dot, porg, 1.5, pvel, (vr_data.realtime + 0.2 + (rnd & 7) * 0.02), (150 + mtwist_rand (&mt) % 6), 1.0, 0.0); } @@ -1477,7 +1477,7 @@ R_EntityParticles_ID (entity_t *ent) forward[1] * beamlength; porg[2] = ent->origin[2] + vertex_normals[i][2] * dist + forward[2] * beamlength; - particle_new (pt_explode, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_explode", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.01, 0x6f, 1.0, 0); } } @@ -1505,7 +1505,7 @@ R_RocketTrail_ID (entity_t *ent) org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; ramp = rnd & 3; - particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_fire", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp); if (numparticles >= r_maxparticles) break; @@ -1537,7 +1537,7 @@ R_GrenadeTrail_ID (entity_t *ent) org[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; ramp = (rnd & 3) + 2; - particle_new (pt_fire, part_tex_dot, org, 1.0, vec3_origin, + particle_new ("pt_fire", part_tex_dot, org, 1.0, vec3_origin, vr_data.realtime + 2.0, ramp3[ramp], 1.0, ramp); if (numparticles >= r_maxparticles) break; @@ -1568,7 +1568,7 @@ R_BloodTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 2.0, 67 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) break; @@ -1599,7 +1599,7 @@ R_SlightBloodTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 9) & 7) * (5.0/7.0) - 2.5; porg[2] = old_origin[2] + ((rnd >> 6) & 7) * (5.0/7.0) - 2.5; - particle_new (pt_grav, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_grav", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 1.5, 67 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) break; @@ -1635,7 +1635,7 @@ R_WizTrail_ID (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel, + particle_new ("pt_static", part_tex_dot, old_origin, 1.0, pvel, vr_data.realtime + 0.5, 52 + ((tracercount & 4) << 1), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1672,7 +1672,7 @@ R_FlameTrail_ID (entity_t *ent) } pvel[2] = 0.0; - particle_new (pt_static, part_tex_dot, old_origin, 1.0, pvel, + particle_new ("pt_static", part_tex_dot, old_origin, 1.0, pvel, vr_data.realtime + 0.5, 230 + ((tracercount & 4) << 1), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1704,7 +1704,7 @@ R_VoorTrail_ID (entity_t *ent) porg[1] = old_origin[1] + ((rnd >> 7) & 15) - 7.5; porg[2] = old_origin[2] + ((rnd >> 11) & 15) - 7.5; - particle_new (pt_static, part_tex_dot, porg, 1.0, vec3_origin, + particle_new ("pt_static", part_tex_dot, porg, 1.0, vec3_origin, vr_data.realtime + 0.3, 9 * 16 + 8 + (rnd & 3), 1.0, 0.0); if (numparticles >= r_maxparticles) @@ -1763,7 +1763,7 @@ build_verts (trailvtx_t *v, GLushort *e) *e++ = index++; *e++ = index++; last_point = point; - point->phys (point); + R_RunParticlePhysics (point); } set_vertex (v++, last_point, -1, bary + bind++, index/2 + 1); set_vertex (v++, last_point, 1, bary + bind++, index/2 + 1); @@ -1964,7 +1964,7 @@ draw_qf_particles (void) vacount += 6; } - part->phys (part); + R_RunParticlePhysics (part); // LordHavoc: immediate removal of unnecessary particles (must be done // to ensure compactor below operates properly in all cases) @@ -2052,7 +2052,7 @@ draw_id_particles (void) vacount++; } - part->phys (part); + R_RunParticlePhysics (part); // LordHavoc: immediate removal of unnecessary particles (must be done // to ensure compactor below operates properly in all cases) @@ -2316,9 +2316,9 @@ glsl_R_Particles_Init_Cvars (void) } void -glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) +glsl_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) { if (numparticles >= r_maxparticles) return; @@ -2326,7 +2326,7 @@ glsl_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, } void -glsl_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, +glsl_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) { diff --git a/libs/video/renderer/particles.part b/libs/video/renderer/particles.part new file mode 100644 index 000000000..23db9a2d4 --- /dev/null +++ b/libs/video/renderer/particles.part @@ -0,0 +1,83 @@ +All of QuakeForge's standard particle physics functions converted to a script +-- pt_static +add_vel + +-- pt_grav +add_vel +add_grav + +-- pt_slowgrav +add_vel +add_grav + +-- pt_fire +add_ramp 5 6 +add_vel +color_ramp3 +alpha_ramp 6 +sub_grav + +-- pt_explode +add_ramp 10 8 +add_vel +color_ramp1 +explode_vel 4 +add_grav + +-- pt_explode2 +add_ramp 15 8 +add_vel +color_ramp2 +explode_vel 1 +add_grav + +-- pt_blob +add_vel +explode_vel 4 +add_grav + +-- pt_blob2 +add_vel +damp_vel 4 +add_grav + +-- pt_smoke +fade_alpha 0.4 +add_vel +grow_scale 4 +//sub_slowgrav + +-- pt_smokecloud +fade_alpha 0.55 +add_vel +grow_scale 50 +sub_slowgrav + +-- pt_bloodcloud +fade_alpha 0.25 +add_vel +grow_scale 4 +add_grav + +-- pt_fadespark +add_vel + +-- pt_fadespark2 +add_vel + +-- pt_fallfade +fade_alpha 1 +add_vel +add_fastgrav + +-- pt_fallfadespark +add_ramp 15 8 +fade_alpha 1 +color_ramp1 +add_vel +add_fastgrav + +-- pt_flame +fade_alpha 0.125 +add_vel +shrink_scale 2 diff --git a/libs/video/renderer/r_part.c b/libs/video/renderer/r_part.c index d49c224b7..cfb7baac9 100644 --- a/libs/video/renderer/r_part.c +++ b/libs/video/renderer/r_part.c @@ -28,14 +28,101 @@ # include "config.h" #endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/cbuf.h" #include "QF/cvar.h" +#include "QF/dstring.h" +#include "QF/hash.h" #include "QF/qargs.h" #include "QF/render.h" +#include "QF/script.h" +#include "QF/segtext.h" #include "QF/sys.h" #include "compat.h" #include "r_internal.h" +typedef enum { + pt_phys_done, + pt_phys_add_vel, + pt_phys_sub_slowgrav, + pt_phys_add_grav, + pt_phys_sub_grav, + pt_phys_add_fastgrav, + pt_phys_add_ramp, // die + pt_phys_fade_alpha, // die + pt_phys_color_ramp1, + pt_phys_color_ramp2, + pt_phys_color_ramp3, + pt_phys_alpha_ramp, + pt_phys_explode_vel, + pt_phys_damp_vel, + pt_phys_grow_scale, + pt_phys_shrink_scale, // die + pt_phys_custom, // die +} pt_phys_e; + +typedef struct { + const char *name; + pt_phys_e opcode; + int num_params; +} pt_phys_opcode_t; + +typedef struct { + char *name; + qboolean (*func) (particle_t *part, void *data); + void *data; +} pt_phys_func_t; + +typedef union pt_phys_op_s { + int32_t op; + float parm; +} pt_phys_op_t; + +typedef struct pt_phys_script_s { + struct pt_phys_script_s *next; + char *name; + pt_phys_op_t *script; +} pt_phys_script_t; + +const char particle_types[] = +#include "particles.pc" +; + +static pt_phys_func_t *phys_funcs; +static int num_phys_funcs; +static int max_phys_funcs; +static pt_phys_script_t *phys_script_freelist; +static hashtab_t *phys_scripts; + +static pt_phys_opcode_t part_phys_opcodes[] = +{ + {"add_vel", pt_phys_add_vel, 0}, + {"sub_slowgrav", pt_phys_sub_slowgrav, 0}, + {"add_grav", pt_phys_add_grav, 0}, + {"sub_grav", pt_phys_sub_grav, 0}, + {"add_fastgrav", pt_phys_add_fastgrav, 0}, + {"add_ramp", pt_phys_add_ramp, 2}, + {"fade_alpha", pt_phys_fade_alpha, 1}, + {"color_ramp1", pt_phys_color_ramp1, 0}, + {"color_ramp2", pt_phys_color_ramp2, 0}, + {"color_ramp3", pt_phys_color_ramp3, 0}, + {"alpha_ramp", pt_phys_alpha_ramp, 1}, + {"explode_vel", pt_phys_explode_vel, 1}, + {"damp_vel", pt_phys_damp_vel, 1}, + {"grow_scale", pt_phys_grow_scale, 1}, + {"shrink_scale", pt_phys_shrink_scale, 1}, + + {0, pt_phys_done, 0}, +}; + unsigned int r_maxparticles, numparticles; particle_t *active_particles, *free_particles, *particles, **freeparticles; vec3_t r_pright, r_pup, r_ppn; @@ -160,152 +247,307 @@ fade_alpha (particle_t *part, float time) return false; } -static void -part_phys_static (particle_t *part) +static inline qboolean +custom_func (particle_t *part, int op) { - add_vel (part); + int func; + func = op - pt_phys_custom; + if (func < 0 || func >= num_phys_funcs) { + Sys_Error ("invalid custom particle physics opcode: %d", op); + } + if (phys_funcs[func].func (part, phys_funcs[func].data)) { + part->die = -1; + return true; + } + return false; } -static void -part_phys_grav (particle_t *part) +void +R_RunParticlePhysics (particle_t *part) { - add_vel (part); - add_grav (part); -} + const pt_phys_op_t *op; + float parm, max; -static void -part_phys_fire (particle_t *part) -{ - if (add_ramp (part, 5.0, 6)) + if (!part->physics) { + // safety net for physicsless particles + add_ramp (part, 1, 4); return; - add_vel (part); - part->color = ramp3[(int) part->ramp]; - part->alpha = (6.0 - part->ramp) / 6.0; - sub_grav (part); + } + for (op = part->physics; ; op++) { + if (op->op >= pt_phys_custom) { + if (custom_func (part, op->op)) + return; + } + + switch ((pt_phys_e) op->op) { + case pt_phys_done: + return; + case pt_phys_add_vel: + add_vel (part); + break; + case pt_phys_sub_slowgrav: + sub_slowgrav (part); + break; + case pt_phys_add_grav: + add_grav (part); + break; + case pt_phys_sub_grav: + sub_grav (part); + break; + case pt_phys_add_fastgrav: + add_fastgrav (part); + break; + case pt_phys_add_ramp: + parm = (++op)->parm; + max = (++op)->parm; + if (add_ramp (part, parm, max)) + return; + break; + case pt_phys_fade_alpha: + parm = (++op)->parm; + if (fade_alpha (part, parm)) + return; + break; + case pt_phys_color_ramp1: + part->color = ramp1[((int) part->ramp) % sizeof (ramp1)]; + break; + case pt_phys_color_ramp2: + part->color = ramp2[((int) part->ramp) % sizeof (ramp2)]; + break; + case pt_phys_color_ramp3: + part->color = ramp3[((int) part->ramp) % sizeof (ramp3)]; + break; + case pt_phys_alpha_ramp: + parm = (++op)->parm; + part->alpha = (parm - part->ramp) / parm; + break; + case pt_phys_explode_vel: + parm = (++op)->parm; + VectorMultAdd (part->vel, vr_data.frametime * parm, part->vel, + part->vel); + break; + case pt_phys_damp_vel: + parm = (++op)->parm; + part->vel[0] -= part->vel[0] * vr_data.frametime * parm; + part->vel[1] -= part->vel[1] * vr_data.frametime * parm; + break; + case pt_phys_grow_scale: + parm = (++op)->parm; + part->scale += vr_data.frametime * parm; + break; + case pt_phys_shrink_scale: + parm = (++op)->parm; + part->scale -= vr_data.frametime * parm; + if (part->scale <= 0.0) { + part->die = -1; + return; + } + break; + case pt_phys_custom: + // handled above + break; + } + } +} + +static pt_phys_opcode_t * +part_find_opcode (const char *name) +{ + pt_phys_opcode_t *op; + + for (op = part_phys_opcodes; op->name; op++) { + if (strcmp (op->name, name) == 0) + return op; + } + return 0; +} + +static pt_phys_func_t * +part_find_function (const char *name) +{ + pt_phys_func_t *func; + + //FIXME is a hash table worth it? + for (func = phys_funcs; func - phys_funcs < num_phys_funcs; func++) { + if (strcmp (func->name, name) == 0) + return func; + } + return 0; } static void -part_phys_explode (particle_t *part) +part_add_op (dstring_t *phys, int op) { - if (add_ramp (part, 10.0, 8)) - return; - add_vel (part); - part->color = ramp1[(int) part->ramp]; - VectorMultAdd (part->vel, vr_data.frametime * 4.0, part->vel, part->vel); - add_grav (part); + int offs = phys->size; + phys->size += sizeof (pt_phys_op_t); + dstring_adjust (phys); + ((pt_phys_op_t *) (phys->str + offs))->op = op; } static void -part_phys_explode2 (particle_t *part) +part_add_parm (dstring_t *phys, float parm) { - if (add_ramp (part, 15.0, 8)) - return; - add_vel (part); - part->color = ramp2[(int) part->ramp]; - VectorMultAdd (part->vel, vr_data.frametime, part->vel, part->vel); - add_grav (part); + int offs = phys->size; + phys->size += sizeof (pt_phys_op_t); + dstring_adjust (phys); + ((pt_phys_op_t *) (phys->str + offs))->parm = parm; +} + +static pt_phys_script_t * +new_phys_script (void) +{ + pt_phys_script_t *phys_script; + ALLOC (16, pt_phys_script_t, phys_script, phys_script); + return phys_script; } static void -part_phys_blob (particle_t *part) +free_phys_script (pt_phys_script_t *phys_script) { - add_vel (part); - VectorMultAdd (part->vel, vr_data.frametime * 4.0, part->vel, part->vel); - add_grav (part); + FREE (phys_script, phys_script); +} + +static const char * +part_script_get_key (const void *_s, void *unused) +{ + const pt_phys_script_t *s = (const pt_phys_script_t *) _s; + return s->name; } static void -part_phys_blob2 (particle_t *part) +part_script_free (void *_s, void *unused) { - add_vel (part); - part->vel[0] -= part->vel[0] * vr_data.frametime * 4.0; - part->vel[1] -= part->vel[1] * vr_data.frametime * 4.0; - add_grav (part); + pt_phys_script_t *s = (pt_phys_script_t *) _s; + free (s->name); + free (s->script); + free_phys_script (s); } -static void -part_phys_smoke (particle_t *part) +qboolean +R_CompileParticlePhysics (const char *name, const char *code) { - if (fade_alpha (part, 0.4)) - return; - add_vel (part); - part->scale += vr_data.frametime * 4.0; - //sub_slowgrav (part); + cbuf_args_t *args = Cbuf_ArgsNew (); + script_t *script = Script_New (); + pt_phys_opcode_t *opcode; + pt_phys_script_t *phys; + pt_phys_func_t *func; + dstring_t *phys_build = dstring_new (); + int i; + qboolean ret = false; + + if (!phys_scripts) { + phys_scripts = Hash_NewTable (61, part_script_get_key, + part_script_free, 0); + } + Script_Start (script, "name", code); + while (Script_GetToken (script, 1)) { + args->argc = 0; + Cbuf_ArgsAdd (args, Script_Token (script)); + while (Script_TokenAvailable (script, 0)) { + Script_GetToken (script, 0); + Cbuf_ArgsAdd (args, Script_Token (script)); + } + Sys_Printf ("%s:%d: %s\n", name, script->line, args->argv[0]->str); + if ((func = part_find_function (args->argv[0]->str))) { + if (args->argc > 1) { + Sys_Printf ("%s:%d: warning: ignoring extra args\n", + name, script->line); + } + part_add_op (phys_build, pt_phys_custom + (func - phys_funcs)); + } else if ((opcode = part_find_opcode (args->argv[0]->str))) { + part_add_op (phys_build, opcode->opcode); + if (args->argc - 1 > opcode->num_params) { + Sys_Printf ("%s:%d: warning: ignoring extra args\n", + name, script->line); + args->argc = opcode->num_params + 1; + } + for (i = 1; i < args->argc; i++) { + char *end; + float parm = strtof (args->argv[i]->str, &end); + if (end == args->argv[i]->str) { + Sys_Printf ("%s:%d: warning: bad float\n", + name, script->line); + } else if (*end) { + Sys_Printf ("%s:%d: warning: ignoring extra chars\n", + name, script->line); + } + part_add_parm (phys_build, parm); + } + if (args->argc - 1 > opcode->num_params) { + Sys_Printf ("%s:%d: warning: setting parms %d+ to zero\n", + name, script->line, args->argc - 1); + for (i--; i < opcode->num_params; i++) + part_add_parm (phys_build, 0); + } + } else { + Sys_Printf ("%s:%d: warning: unknown opcode/function: %s\n", + name, script->line, args->argv[0]->str); + } + } + if (phys_build->size) { + part_add_op (phys_build, pt_phys_done); + phys = new_phys_script (); + phys->name = strdup (name); + phys->script = (pt_phys_op_t *) dstring_freeze (phys_build); + Hash_Add (phys_scripts, phys); + ret = true; + } else { + dstring_delete (phys_build); + } + + Script_Delete (script); + Cbuf_ArgsDelete (args); + return ret; } -static void -part_phys_smokecloud (particle_t *part) +const pt_phys_op_t * +R_ParticlePhysics (const char *type) { - if (fade_alpha (part, 0.55)) - return; - add_vel (part); - part->scale += vr_data.frametime * 50.0; - sub_slowgrav (part); + pt_phys_script_t *phys; + + if (!phys_scripts) + return 0; + if ((phys = Hash_Find (phys_scripts, type))) + return phys->script; + return 0; } -static void -part_phys_bloodcloud (particle_t *part) +qboolean +R_AddParticlePhysicsFunction (const char *name, + qboolean (*func) (particle_t *part, void *data), + void *data) { - if (fade_alpha (part, 0.25)) - return; - add_vel (part); - part->scale += vr_data.frametime * 4.0; - add_grav (part); + int i; + + for (i = 0; i < num_phys_funcs; i++) { + if (strcmp (name, phys_funcs[i].name) == 0) + return false; + } + if (num_phys_funcs == max_phys_funcs) { + max_phys_funcs += 16; + phys_funcs = realloc (phys_funcs, + max_phys_funcs * sizeof (pt_phys_func_t)); + if (!phys_funcs) { + Sys_Error ("R_AddParticlePhysicsFunction: out of memory"); + } + } + phys_funcs[num_phys_funcs].name = strdup (name); + phys_funcs[num_phys_funcs].func = func; + phys_funcs[num_phys_funcs].data = data; + return true; } -static void -part_phys_fallfade (particle_t *part) +void +R_LoadParticles (void) { - if (fade_alpha (part, 1.0)) - return; - add_vel (part); - add_fastgrav (part); -} + segtext_t *text; + segchunk_t *chunk; -static void -part_phys_fallfadespark (particle_t *part) -{ - if (add_ramp (part, 15.0, 8)) - return; - if (fade_alpha (part, 1.0)) - return; - part->color = ramp1[(int) part->ramp]; - add_vel (part); - add_fastgrav (part); -} - -static void -part_phys_flame (particle_t *part) -{ - if (fade_alpha (part, 0.125)) - return; - add_vel (part); - part->scale -= vr_data.frametime * 2.0; -} - -static pt_phys_func part_phys[] = { - part_phys_static, // pt_static - part_phys_grav, // pt_grav - part_phys_grav, // pt_slowgrav - part_phys_fire, // pt_fire - part_phys_explode, // pt_explode - part_phys_explode2, // pt_explode2 - part_phys_blob, // pt_blob - part_phys_blob2, // pt_blob2 - part_phys_smoke, // pt_smoke - part_phys_smokecloud, // pt_smokecloud - part_phys_bloodcloud, // pt_bloodcloud - part_phys_static, // pt_fadespark - part_phys_static, // pt_fadespark2 - part_phys_fallfade, // pt_fallfade - part_phys_fallfadespark,// pt_fallfadespark - part_phys_flame, // pt_flame -}; - -pt_phys_func -R_ParticlePhysics (ptype_t type) -{ - if (type > pt_flame) - Sys_Error ("R_ParticlePhysics: invalid particle type"); - return part_phys[type]; + text = Segtext_new (particle_types); + for (chunk = text->chunk_list; chunk; chunk = chunk->next) { + if (chunk->tag) { + Sys_Printf ("compiling %s\n", chunk->tag); + R_CompileParticlePhysics (chunk->tag, chunk->text); + } + } } diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 5d38ae04d..0ed1655a7 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -128,6 +128,7 @@ sw_R_Init (void) #ifdef USE_INTEL_ASM R_InitVars (); #endif + R_InitParticles (); R_InitTurb (); diff --git a/libs/video/renderer/sw/sw_rpart.c b/libs/video/renderer/sw/sw_rpart.c index 4e113cc5b..71ee1fcf8 100644 --- a/libs/video/renderer/sw/sw_rpart.c +++ b/libs/video/renderer/sw/sw_rpart.c @@ -56,6 +56,7 @@ static mtstate_t mt; // private PRNG state void R_InitParticles (void) { + R_LoadParticles (); mtwist_seed (&mt, 0xdeadbeef); } @@ -119,8 +120,7 @@ R_ReadPointFile_f (void) p->die = 99999; p->color = (-c) & 15; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); VectorZero (p->vel); VectorCopy (org, p->org); } @@ -150,10 +150,9 @@ R_ParticleExplosion_QF (const vec3_t org) p->color = ramp1[0]; p->ramp = mtwist_rand (&mt) & 3; if (i & 1) - p->type = pt_explode; + p->physics = R_ParticlePhysics ("pt_explode"); else - p->type = pt_explode2; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_explode2"); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; @@ -180,8 +179,7 @@ R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) p->color = colorStart + (colorMod % colorLength); colorMod++; - p->type = pt_blob; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_blob"); for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt)%32)-16); p->vel[j] = (mtwist_rand (&mt)%512)-256; @@ -209,13 +207,12 @@ R_BlobExplosion_QF (const vec3_t org) p->die = vr_data.realtime + 1 + (mtwist_rand (&mt) & 8) * 0.05; if (i & 1) { - p->type = pt_blob; p->color = 66 + mtwist_rand (&mt) % 6; + p->physics = R_ParticlePhysics ("pt_blob"); } else { - p->type = pt_blob2; p->color = 150 + mtwist_rand (&mt) % 6; + p->physics = R_ParticlePhysics ("pt_blob2"); } - p->phys = R_ParticlePhysics (p->type); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; @@ -243,8 +240,7 @@ R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, p->die = vr_data.realtime + 0.1 * (mtwist_rand (&mt) % 5); p->color = (color & ~7) + (mtwist_rand (&mt) & 7); - p->type = pt_grav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_grav"); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) & 15) - 8); p->vel[j] = dir[j]; // + (mtwist_rand (&mt)%300)-150; @@ -317,8 +313,7 @@ R_LavaSplash_QF (const vec3_t org) p->die = vr_data.realtime + 2 + (mtwist_rand (&mt) & 31) * 0.02; p->color = 224 + (mtwist_rand (&mt) & 7); - p->type = pt_grav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_grav"); dir[0] = j * 8 + (mtwist_rand (&mt) & 7); dir[1] = i * 8 + (mtwist_rand (&mt) & 7); @@ -357,8 +352,7 @@ R_TeleportSplash_QF (const vec3_t org) p->die = vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02; p->color = 7 + (mtwist_rand (&mt) & 7); - p->type = pt_grav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_grav"); dir[0] = j * 8; dir[1] = i * 8; @@ -403,8 +397,7 @@ R_DarkFieldParticles_ID (entity_t *ent) p->die = vr_data.realtime + 0.2 + (rnd & 7) * 0.02; p->color = 150 + mtwist_rand (&mt) % 6; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); dir[0] = j * 8; dir[1] = i * 8; dir[2] = k * 8; @@ -467,8 +460,7 @@ R_EntityParticles_ID (entity_t *ent) p->die = vr_data.realtime + 0.01; p->color = 0x6f; - p->type = pt_explode; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_explode"); p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; @@ -509,8 +501,7 @@ R_RocketTrail_QF (entity_t *ent) p->die = vr_data.realtime + 2; p->ramp = (mtwist_rand (&mt) & 3); p->color = ramp3[(int) p->ramp]; - p->type = pt_fire; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_fire"); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -548,8 +539,7 @@ R_GrenadeTrail_QF (entity_t *ent) p->die = vr_data.realtime + 2; p->ramp = (mtwist_rand (&mt) & 3) + 2; p->color = ramp3[(int) p->ramp]; - p->type = pt_fire; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_fire"); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -585,8 +575,7 @@ R_BloodTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 2; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -624,8 +613,7 @@ R_SlightBloodTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 2; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -661,8 +649,7 @@ R_WizTrail_QF (entity_t *ent) active_particles = p; p->die = vr_data.realtime + 0.5; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 52 + ((tracercount & 4) << 1); tracercount++; @@ -708,8 +695,7 @@ R_FlameTrail_QF (entity_t *ent) active_particles = p; p->die = vr_data.realtime + 0.5; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 230 + ((tracercount & 4) << 1); tracercount++; @@ -756,8 +742,7 @@ R_VoorTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 0.3; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 9 * 16 + 8 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) & 15) - 8); @@ -787,7 +772,7 @@ R_DrawParticles (void) D_DrawParticle (p); - p->phys (p); + R_RunParticlePhysics (p); } } } @@ -877,7 +862,7 @@ R_Particles_Init_Cvars (void) } void -R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, +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) { particle_t *p; @@ -895,16 +880,15 @@ R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, p->scale = scale; p->alpha = alpha; VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics (type); p->die = die; p->ramp = ramp; } void -R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, int org_fuzz, - float scale, int vel_fuzz, float die, int color, - float alpha, float ramp) +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) { float o_fuzz = org_fuzz, v_fuzz = vel_fuzz; int rnd; diff --git a/libs/video/renderer/sw32/sw32_rmain.c b/libs/video/renderer/sw32/sw32_rmain.c index fd204e587..9ff2dc40f 100644 --- a/libs/video/renderer/sw32/sw32_rmain.c +++ b/libs/video/renderer/sw32/sw32_rmain.c @@ -150,6 +150,7 @@ sw32_R_Init (void) sw32_Draw_Init (); SCR_Init (); + R_InitParticles (); sw32_R_InitTurb (); Cmd_AddCommand ("timerefresh", sw32_R_TimeRefresh_f, "Tests the current " diff --git a/libs/video/renderer/sw32/sw32_rpart.c b/libs/video/renderer/sw32/sw32_rpart.c index 0ba04ca1b..24e6a7876 100644 --- a/libs/video/renderer/sw32/sw32_rpart.c +++ b/libs/video/renderer/sw32/sw32_rpart.c @@ -60,6 +60,7 @@ static mtstate_t mt; // private PRNG state void sw32_R_InitParticles (void) { + R_LoadParticles (); mtwist_seed (&mt, 0xdeadbeef); } @@ -124,8 +125,7 @@ sw32_R_ReadPointFile_f (void) p->die = 99999; p->color = (-c) & 15; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); VectorZero (p->vel); VectorCopy (org, p->org); } @@ -155,19 +155,18 @@ R_ParticleExplosion_QF (const vec3_t org) p->color = ramp1[0]; p->ramp = mtwist_rand (&mt) & 3; if (i & 1) { - p->type = pt_explode; + p->physics = R_ParticlePhysics ("pt_explode"); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; } } else { - p->type = pt_explode2; + p->physics = R_ParticlePhysics ("pt_explode2"); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; } } - p->phys = R_ParticlePhysics (p->type); } } @@ -191,8 +190,7 @@ R_ParticleExplosion2_QF (const vec3_t org, int colorStart, int colorLength) p->color = colorStart + (colorMod % colorLength); colorMod++; - p->type = pt_blob; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_blob"); for (j=0 ; j<3 ; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt)%32)-16); @@ -221,21 +219,20 @@ R_BlobExplosion_QF (const vec3_t org) p->die = vr_data.realtime + 1 + (mtwist_rand (&mt) & 8) * 0.05; if (i & 1) { - p->type = pt_blob; + p->physics = R_ParticlePhysics ("pt_blob"); p->color = 66 + mtwist_rand (&mt) % 6; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; } } else { - p->type = pt_blob2; + p->physics = R_ParticlePhysics ("pt_blob2"); p->color = 150 + mtwist_rand (&mt) % 6; for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) % 32) - 16); p->vel[j] = (mtwist_rand (&mt) % 512) - 256; } } - p->phys = R_ParticlePhysics (p->type); } } @@ -262,8 +259,7 @@ R_LavaSplash_QF (const vec3_t org) p->die = vr_data.realtime + 2 + (mtwist_rand (&mt) & 31) * 0.02; p->color = 224 + (mtwist_rand (&mt) & 7); - p->type = pt_grav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_grav"); dir[0] = j * 8 + (mtwist_rand (&mt) & 7); dir[1] = i * 8 + (mtwist_rand (&mt) & 7); @@ -302,8 +298,7 @@ R_TeleportSplash_QF (const vec3_t org) p->die = vr_data.realtime + 0.2 + (mtwist_rand (&mt) & 7) * 0.02; p->color = 7 + (mtwist_rand (&mt) & 7); - p->type = pt_grav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_grav"); dir[0] = j * 8; dir[1] = i * 8; @@ -347,8 +342,7 @@ R_DarkFieldParticles_ID (entity_t *ent) p->die = vr_data.realtime + 0.2 + (rnd & 7) * 0.02; p->color = 150 + mtwist_rand (&mt) % 6; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); dir[0] = j * 8; dir[1] = i * 8; @@ -409,8 +403,7 @@ R_EntityParticles_ID (entity_t *ent) p->die = vr_data.realtime + 0.01; p->color = 0x6f; - p->type = pt_explode; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_explode"); p->org[0] = ent->origin[0] + r_avertexnormals[i][0] * dist + forward[0] * beamlength; @@ -441,8 +434,7 @@ R_RunParticleEffect_QF (const vec3_t org, const vec3_t dir, int color, p->die = vr_data.realtime + 0.1 * (mtwist_rand (&mt) % 5); p->color = (color & ~7) + (mtwist_rand (&mt) & 7); - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); for (j = 0; j < 3; j++) { p->org[j] = org[j] + ((mtwist_rand (&mt) & 15) - 8); p->vel[j] = dir[j]; // + (mtwist_rand (&mt)%300)-150; @@ -522,8 +514,7 @@ R_RocketTrail_QF (entity_t *ent) p->die = vr_data.realtime + 2; p->ramp = (mtwist_rand (&mt) & 3); p->color = ramp3[(int) p->ramp]; - p->type = pt_fire; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_fire"); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -561,8 +552,7 @@ R_GrenadeTrail_QF (entity_t *ent) p->die = vr_data.realtime + 2; p->ramp = (mtwist_rand (&mt) & 3) + 2; p->color = ramp3[(int) p->ramp]; - p->type = pt_fire; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_fire"); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -598,8 +588,7 @@ R_BloodTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 2; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -637,8 +626,7 @@ R_SlightBloodTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 2; - p->type = pt_slowgrav; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_slowgrav"); p->color = 67 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) % 6) - 3); @@ -674,8 +662,7 @@ R_WizTrail_QF (entity_t *ent) active_particles = p; p->die = vr_data.realtime + 0.5; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 52 + ((tracercount & 4) << 1); tracercount++; @@ -721,8 +708,7 @@ R_FlameTrail_QF (entity_t *ent) active_particles = p; p->die = vr_data.realtime + 0.5; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 230 + ((tracercount & 4) << 1); tracercount++; @@ -769,8 +755,7 @@ R_VoorTrail_QF (entity_t *ent) VectorZero (p->vel); p->die = vr_data.realtime + 0.3; - p->type = pt_static; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics ("pt_static"); p->color = 9 * 16 + 8 + (mtwist_rand (&mt) & 3); for (j = 0; j < 3; j++) p->org[j] = old_origin[j] + ((mtwist_rand (&mt) & 15) - 8); @@ -800,7 +785,7 @@ sw32_R_DrawParticles (void) sw32_D_DrawParticle (p); - p->phys (p); + R_RunParticlePhysics (p); } } } @@ -890,9 +875,9 @@ sw32_R_Particles_Init_Cvars (void) } void -sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, - const vec3_t vel, float die, int color, float alpha, - float ramp) +sw32_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) { particle_t *p; @@ -909,14 +894,13 @@ sw32_R_Particle_New (ptype_t type, int texnum, const vec3_t org, float scale, p->scale = scale; p->alpha = alpha; VectorCopy (vel, p->vel); - p->type = type; - p->phys = R_ParticlePhysics (p->type); + p->physics = R_ParticlePhysics (type); p->die = die; p->ramp = ramp; } void -sw32_R_Particle_NewRandom (ptype_t type, int texnum, const vec3_t org, +sw32_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) { diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index c79bfaa20..d874a0258 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -114,6 +114,8 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_R_RenderView, R_DecayLights, gl_R_ViewChanged, + R_CompileParticlePhysics, + R_AddParticlePhysicsFunction, gl_R_ClearParticles, gl_R_InitParticles, gl_SCR_ScreenShot_f, diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index f09820ab3..635e7b415 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -114,6 +114,8 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_R_RenderView, R_DecayLights, glsl_R_ViewChanged, + R_CompileParticlePhysics, + R_AddParticlePhysicsFunction, glsl_R_ClearParticles, glsl_R_InitParticles, glsl_SCR_ScreenShot_f, diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index 7ac10a4d4..1e933a0dd 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -107,6 +107,8 @@ vid_render_funcs_t sw_vid_render_funcs = { R_RenderView, R_DecayLights, R_ViewChanged, + R_CompileParticlePhysics, + R_AddParticlePhysicsFunction, R_ClearParticles, R_InitParticles, SCR_ScreenShot_f, diff --git a/libs/video/renderer/vid_render_sw32.c b/libs/video/renderer/vid_render_sw32.c index 9bc135c78..9660f5afb 100644 --- a/libs/video/renderer/vid_render_sw32.c +++ b/libs/video/renderer/vid_render_sw32.c @@ -112,6 +112,8 @@ vid_render_funcs_t sw32_vid_render_funcs = { sw32_R_RenderView, R_DecayLights, sw32_R_ViewChanged, + R_CompileParticlePhysics, + R_AddParticlePhysicsFunction, sw32_R_ClearParticles, sw32_R_InitParticles, sw32_SCR_ScreenShot_f, diff --git a/qw/source/cl_ents.c b/qw/source/cl_ents.c index edd048090..5661b1b0f 100644 --- a/qw/source/cl_ents.c +++ b/qw/source/cl_ents.c @@ -613,12 +613,12 @@ CL_EmitEntities (void) dl->color[3] = 0.7; } VectorCopy (nearloc->loc, trueloc); - r_funcs->particles->R_Particle_New (pt_smokecloud, part_tex_smoke, + r_funcs->particles->R_Particle_New ("pt_smokecloud", part_tex_smoke, trueloc, 2.0, vec3_origin, r_data->realtime + 9.0, 254, 0.25 + qfrandom (0.125), 0.0); for (i = 0; i < 15; i++) - r_funcs->particles->R_Particle_NewRandom (pt_fallfade, + r_funcs->particles->R_Particle_NewRandom ("pt_fallfade", part_tex_dot, trueloc, 12, 0.7, 96, r_data->realtime + 5.0, 104 + (rand () & 7), 1.0, 0.0); From 4258f0408a9ad1b4ee4b869ad8bb9c40ab15317b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 31 Jan 2014 11:59:07 +0900 Subject: [PATCH 14/31] Remove the version controls. They cause problems where they are. When I need them, all add them as appropriate at the time. --- libs/video/renderer/glsl/sgustavson.glsl | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/libs/video/renderer/glsl/sgustavson.glsl b/libs/video/renderer/glsl/sgustavson.glsl index de7d86553..641df2f03 100644 --- a/libs/video/renderer/glsl/sgustavson.glsl +++ b/libs/video/renderer/glsl/sgustavson.glsl @@ -79,8 +79,6 @@ vec4 taylorInvSqrt(vec4 r) // License : Copyright (C) 2011 Ashima Arts. All rights reserved. // Distributed under the MIT License. See LICENSE file. -#version 120 - float snoise(vec3 v) { const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; @@ -155,8 +153,6 @@ float snoise(vec3 v) -- Vertex.simplex -#version 120 - uniform float time; varying vec3 vTexCoord3D; @@ -177,8 +173,6 @@ void main( void ) -- Vertex.flame -#version 120 - uniform float time; varying vec3 vTexCoord3D; @@ -291,8 +285,6 @@ float srdnoise(in vec2 P, in float rot, out vec2 grad) { -- Vertex.flow -#version 120 - varying vec2 vTexCoord2D; void main(void) { @@ -316,8 +308,6 @@ void main(void) { -- Noise.spots -#version 120 - // Cellular noise ("Worley noise") in 3D in GLSL. // Copyright (c) Stefan Gustavson 2011-04-19. All rights reserved. // This code is released under the conditions of the MIT license. @@ -383,8 +373,6 @@ vec2 cellular2x2x2(vec3 P) -- Vertex.spots -#version 120 - uniform float time; varying vec3 vTexCoord3D; @@ -581,8 +569,6 @@ vec2 cellular(vec3 P) -- Vertex.tile -#version 120 - uniform float time; varying vec3 vTexCoord3D; @@ -597,8 +583,6 @@ void main(void) { -- Fragment.tile -#version 120 - varying vec3 vTexCoord3D; void main(void) { From 77fa66b2e83f192fed1ff1f4abd5127b3a7ff15e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 31 Jan 2014 12:00:19 +0900 Subject: [PATCH 15/31] Properly separate the two glsl files in C. --- libs/video/renderer/glsl/vid_common_glsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/glsl/vid_common_glsl.c b/libs/video/renderer/glsl/vid_common_glsl.c index 3fb0b9707..05c430f93 100644 --- a/libs/video/renderer/glsl/vid_common_glsl.c +++ b/libs/video/renderer/glsl/vid_common_glsl.c @@ -58,7 +58,7 @@ static const char quakeforge_effect[] = #include "quakeforge.slc" -"--" // ensure the last block of the previous file doesn't merge with +"--\n" // ensure the last block of the previous file doesn't merge with // the first block of the next file // Include Stefan Gustavson's noise functions in the QuakeForge shader // effect "file". From f8b5fc2842a77f884e1c1bcc435b3412e18c3f3d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 31 Jan 2014 12:01:20 +0900 Subject: [PATCH 16/31] Use multi-octave simplex noise for the smoke trails. It looks ok-ish, but still needs a lot of work. --- libs/video/renderer/glsl/glsl_particles.c | 36 ++++++++++++++++++----- libs/video/renderer/glsl/quakeforge.glsl | 23 ++++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index e681aa01f..df3d517d3 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -115,7 +115,10 @@ static const char *particle_trail_vert_effects[] = static const char *particle_trail_frag_effects[] = { - "QuakeForge.Fragment.barycentric", + "QuakeForge.Math.InvSqrt", + "QuakeForge.Math.permute", + "QuakeForge.Noise.simplex", + "QuakeForge.Fragment.particle.trail", 0 }; @@ -164,7 +167,8 @@ static struct { shaderparam_t next; shaderparam_t barycentric; shaderparam_t texoff; - shaderparam_t smoke; + shaderparam_t colora; + shaderparam_t colorb; } trail = { 0, {"proj", 1}, @@ -176,7 +180,8 @@ static struct { {"next", 0}, {"barycentric", 0}, {"texoff", 0}, - {"smoke", 1}, + {"vcolora", 0}, + {"vcolorb", 0}, }; typedef struct trail_s { @@ -192,6 +197,8 @@ typedef struct trailvtx_s { quat_t vertex; vec3_t bary; float texoff; + quat_t colora; + quat_t colorb; } trailvtx_t; static trail_t *trails_freelist; @@ -369,7 +376,8 @@ glsl_R_InitParticles (void) GLSL_ResolveShaderParam (trail.program, &trail.next); GLSL_ResolveShaderParam (trail.program, &trail.barycentric); GLSL_ResolveShaderParam (trail.program, &trail.texoff); - GLSL_ResolveShaderParam (trail.program, &trail.smoke); + GLSL_ResolveShaderParam (trail.program, &trail.colora); + GLSL_ResolveShaderParam (trail.program, &trail.colorb); GLSL_FreeShader (vert_shader); GLSL_FreeShader (frag_shader); @@ -754,19 +762,20 @@ R_RocketTrail_trail (entity_t *ent) pscale = 1.5 + qfrandom (1.5); while (len < maxlen) { + int ramp; pscalenext = 1.5 + qfrandom (1.5); dist = (pscale + pscalenext) * 3.0; percent = len * origlen; point = new_point (); VectorCopy (old_origin, point->org); - point->color = 12 + (mtwist_rand (&mt) & 3); + 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 = 0.0; + point->ramp = ramp; point->physics = R_ParticlePhysics ("pt_fire"); *ent->trail->head = point; @@ -1718,10 +1727,15 @@ 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; + 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 @@ -1818,6 +1832,8 @@ draw_trails (void) 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); @@ -1836,6 +1852,10 @@ draw_trails (void) 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 (trl = trails_active; trl; trl = trl->next) { int count; @@ -1853,6 +1873,8 @@ draw_trails (void) if (trail.barycentric.location >= 0) qfeglDisableVertexAttribArray (trail.barycentric.location); qfeglDisableVertexAttribArray (trail.texoff.location); + qfeglDisableVertexAttribArray (trail.colora.location); + qfeglDisableVertexAttribArray (trail.colorb.location); expire_trails (); } diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index 80ff0cf4e..9326b884e 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -584,6 +584,8 @@ main (void) attribute vec4 last, current, next; attribute vec3 barycentric; attribute float texoff; +attribute vec4 vcolora; +attribute vec4 vcolorb; uniform mat4 proj, view; uniform vec2 viewport; @@ -591,6 +593,8 @@ uniform float width; varying vec2 texcoord; varying vec3 vbarycentric; +varying vec4 colora; +varying vec4 colorb; vec4 transform (vec3 coord) @@ -634,7 +638,9 @@ main (void) vec2 sCurrent = project (dCurrent); float off = current.w; - texcoord = vec2 (texoff * 0.7, off * 0.5 + 0.5); + colora = vcolora; + colorb = vcolorb; + texcoord = vec2 (texoff * 0.7, off);// * 0.5 + 0.5); vbarycentric = barycentric; t = sLast - sCurrent; @@ -663,14 +669,23 @@ main (void) -- Fragment.particle.trail -uniform sampler2D smoke; - varying vec2 texcoord; +varying vec4 colora; +varying vec4 colorb; void main (void) { - gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); + //gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); + vec3 tex3 = vec3 (texcoord, 0.5); + float n = abs(snoise(tex3)); + float a = sqrt(1.0 - texcoord.y * texcoord.y); + n += 0.5 * abs(snoise(tex3 * 2.0)); + n += 0.25 * abs(snoise(tex3 * 4.0)); + n += 0.125 * abs(snoise(tex3 * 8.0)); + vec4 c = colora + colorb * n; + c.a *= a; + gl_FragColor = c; } -- Fragment.barycentric From 7170a434eee884a793291fcbd30fec85f998f092 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Jan 2016 20:12:48 +0900 Subject: [PATCH 17/31] Split out the trail adding code. This makes it easier to add multiple trails to one entity, or even better: to add other types of trails. --- libs/video/renderer/glsl/glsl_particles.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index df3d517d3..5563808b3 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -737,6 +737,18 @@ R_TeleportSplash_QF (const vec3_t org) } } +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 void R_RocketTrail_trail (entity_t *ent) { @@ -746,13 +758,7 @@ R_RocketTrail_trail (entity_t *ent) particle_t *point; if (!ent->trail) { - 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; + add_trail_to_ent (ent); } VectorCopy (ent->old_origin, old_origin); From bb63335fe14d672f265e1bf02a2bbc12d02dbfe5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Jan 2016 20:27:03 +0900 Subject: [PATCH 18/31] Rewrite trail vertex list building. Most important change is to use the arrays directly rather than using element indices. I don't remember why I did it that way as it gained nothing and using arrays directly is much simpler. Also, the "dummy" vertices at either end of the trail are no longer duplicates of the end vertices, but are now extrapolations. This fixes up the weirdness at either end of the trails. --- libs/video/renderer/glsl/glsl_particles.c | 64 ++++++++++++----------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 5563808b3..42e8fe924 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -1736,7 +1736,9 @@ set_vertex (trailvtx_t *v, const particle_t *point, float w, const vec3_t bary, byte *color = (byte *) &d_8to24table[(byte) point->color]; VectorCopy (point->org, v->vertex); - VectorCopy (bary, v->bary); + if (bary) { + VectorCopy (bary, v->bary); + } v->vertex[3] = w * point->scale; v->texoff = off; VectorScale (color, 1.5 / 255, v->colora); @@ -1745,49 +1747,54 @@ set_vertex (trailvtx_t *v, const particle_t *point, float w, const vec3_t bary, } static void -count_points (int *num_verts, int *num_elements) +count_points (int *num_verts) { trail_t *trail; *num_verts = 0; - *num_elements = 0; for (trail = trails_active; trail; trail = trail->next) { if (trail->num_points < 2) continue; - // +2 for an extra point at either end of the strip + // 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; - *num_elements += trail->num_points * 2; } } static void -build_verts (trailvtx_t *v, GLushort *e) +build_verts (trailvtx_t *v) { trail_t *trail; - int index = 0; - particle_t *point, *last_point = 0; + 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; - set_vertex (v++, point, -1, bary + bind++, index/2); - set_vertex (v++, point, 1, bary + bind++, index/2); - bind %= 3; - for (; point; point = point->next) { - set_vertex (v++, point, -1, bary + bind++, index/2 + 1); - set_vertex (v++, point, 1, bary + bind++, index/2 + 1); - bind %= 3; - *e++ = index++; - *e++ = index++; + VectorScale (point->org, 2, dup.org); + VectorSubtract (dup.org, point->next->org, dup.org); + set_vertex (v++, &dup, -1, 0, 0); + set_vertex (v++, &dup, +1, 0, 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); } - set_vertex (v++, last_point, -1, bary + bind++, index/2 + 1); - set_vertex (v++, last_point, 1, bary + bind++, index/2 + 1); - index += 4; + VectorScale (last_point->org, 2, dup.org); + VectorSubtract (dup.org, second_last_point->org, dup.org); + set_vertex (v++, &dup, -1, 0, 0); + set_vertex (v++, &dup, +1, 0, 0); } } @@ -1819,17 +1826,15 @@ draw_trails (void) { trail_t *trl; int num_verts; - int num_elements; + int first; trailvtx_t *verts; - GLushort *elements; - count_points (&num_verts, &num_elements); - if (!num_elements) + count_points (&num_verts); + if (!num_verts) return; verts = alloca (num_verts * sizeof (trailvtx_t)); - elements = alloca (num_verts * sizeof (GLushort)); - build_verts (verts, elements); + build_verts (verts); qfeglUseProgram (trail.program); qfeglEnableVertexAttribArray (trail.last.location); @@ -1863,14 +1868,13 @@ draw_trails (void) qfeglVertexAttribPointer (trail.colorb.location, 4, GL_FLOAT, 0, sizeof (trailvtx_t), &verts[0].colorb); - for (trl = trails_active; trl; trl = trl->next) { + for (first = 0, trl = trails_active; trl; trl = trl->next) { int count; if (trl->num_points < 2) continue; count = trl->num_points * 2; - qfeglDrawElements (GL_TRIANGLE_STRIP, count, GL_UNSIGNED_SHORT, - elements); - elements += count; + qfeglDrawArrays (GL_TRIANGLE_STRIP, first, count); + first += count + 4; } qfeglDisableVertexAttribArray (trail.last.location); From cdce665de115f4b51eeef88e9b293640c7e5a26a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 25 Jan 2016 20:31:36 +0900 Subject: [PATCH 19/31] Add a pt_float particle physics script. This is similar to pt_fire, but without the color effects. For now, it is useful for testing trails. --- libs/video/renderer/particles.part | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/video/renderer/particles.part b/libs/video/renderer/particles.part index 23db9a2d4..b868ef926 100644 --- a/libs/video/renderer/particles.part +++ b/libs/video/renderer/particles.part @@ -17,6 +17,10 @@ color_ramp3 alpha_ramp 6 sub_grav +-- pt_float +add_vel +sub_grav + -- pt_explode add_ramp 10 8 add_vel From fff6d799b610415c48ea5aa1e32c6cf68fac7b7e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2016 20:47:50 +0900 Subject: [PATCH 20/31] Always pass bary to set_vertex. The contents of the barycentric coordinatess in the vertex data don't matter for the dummy vertices, so skip the if and just use the first barycentric coordinate. --- libs/video/renderer/glsl/glsl_particles.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 42e8fe924..cb38cb07c 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -1736,9 +1736,7 @@ set_vertex (trailvtx_t *v, const particle_t *point, float w, const vec3_t bary, byte *color = (byte *) &d_8to24table[(byte) point->color]; VectorCopy (point->org, v->vertex); - if (bary) { - VectorCopy (bary, v->bary); - } + VectorCopy (bary, v->bary); v->vertex[3] = w * point->scale; v->texoff = off; VectorScale (color, 1.5 / 255, v->colora); @@ -1780,8 +1778,8 @@ build_verts (trailvtx_t *v) point = trail->points; VectorScale (point->org, 2, dup.org); VectorSubtract (dup.org, point->next->org, dup.org); - set_vertex (v++, &dup, -1, 0, 0); - set_vertex (v++, &dup, +1, 0, 0); + 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; @@ -1793,8 +1791,8 @@ build_verts (trailvtx_t *v) } VectorScale (last_point->org, 2, dup.org); VectorSubtract (dup.org, second_last_point->org, dup.org); - set_vertex (v++, &dup, -1, 0, 0); - set_vertex (v++, &dup, +1, 0, 0); + set_vertex (v++, &dup, -1, bary, 0); + set_vertex (v++, &dup, +1, bary, 0); } } From db6e0faae46b75fd569fd7a6f064a5260db781a6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 27 Jan 2016 20:51:10 +0900 Subject: [PATCH 21/31] Clean up R_RocketTrail_trail a bit. In preparation for a redesign of the trail creation. --- libs/video/renderer/glsl/glsl_particles.c | 44 +++++++++++++++-------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index cb38cb07c..9db84212e 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -749,6 +749,34 @@ add_trail_to_ent (entity_t *ent) 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) { @@ -768,25 +796,13 @@ R_RocketTrail_trail (entity_t *ent) pscale = 1.5 + qfrandom (1.5); while (len < maxlen) { - int ramp; pscalenext = 1.5 + qfrandom (1.5); dist = (pscale + pscalenext) * 3.0; percent = len * origlen; - point = new_point (); - VectorCopy (old_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_fire"); + point = new_trail_point (old_origin, pscale, percent); - *ent->trail->head = point; - ent->trail->head = &point->next; - ent->trail->num_points++; + add_point_to_trail (ent->trail, point); len += dist; VectorMultAdd (old_origin, len, vec, old_origin); From 6b2e45cae68d9ff5ff49c61335ce831442805a3a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Feb 2016 12:30:47 +0900 Subject: [PATCH 22/31] Fix shader line numbers being out by one. --- libs/video/renderer/glsl/glsl_shader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/renderer/glsl/glsl_shader.c b/libs/video/renderer/glsl/glsl_shader.c index d38bb2c29..cddb2a617 100644 --- a/libs/video/renderer/glsl/glsl_shader.c +++ b/libs/video/renderer/glsl/glsl_shader.c @@ -129,7 +129,7 @@ GLSL_BuildShader (const char **effect_keys) Sys_Printf ("Unknown shader key: '%s'\n", dot); goto error; } - shader->strings[num] = nva ("#line %d\n%s", chunk->start_line, + shader->strings[num] = nva ("#line %d\n%s", chunk->start_line - 1, chunk->text); shader->src[num] = strdup (ekey->str); } From 11c2d8f4226dd4aaca354f66e74f6fbb55cd5da4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 13 Feb 2016 16:59:56 +0900 Subject: [PATCH 23/31] Rework the trails vertex shader to be reusable. --- libs/video/renderer/glsl/glsl_particles.c | 7 +- libs/video/renderer/glsl/quakeforge.glsl | 160 +++++++++++++--------- 2 files changed, 101 insertions(+), 66 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_particles.c b/libs/video/renderer/glsl/glsl_particles.c index 9db84212e..1da8add27 100644 --- a/libs/video/renderer/glsl/glsl_particles.c +++ b/libs/video/renderer/glsl/glsl_particles.c @@ -109,6 +109,9 @@ static const char *particle_textured_frag_effects[] = 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 }; @@ -171,8 +174,8 @@ static struct { shaderparam_t colorb; } trail = { 0, - {"proj", 1}, - {"view", 1}, + {"projection_mat", 1}, + {"view_mat", 1}, {"viewport", 1}, {"width", 1}, {"last", 0}, diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index 9326b884e..e9bfa4d69 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -50,6 +50,100 @@ dqtrans (vec4 q0, vec4 qe) return 2.0 * (Ts * qv + qs * Tv + cross (Tv, qv)); } +-- Vertex.transform.mvp +uniform mat4 mvp_mat; + +-- Vertex.transform.view_projection +uniform mat4 projection_mat, view_mat; + +-- Screen.viewport +uniform vec2 viewport; + +-- Vertex.ScreenSpace.curve.width + +vec2 +project (vec4 coord) +{ + vec3 device = coord.xyz / coord.w; + vec2 clip = (device * 0.5 + 0.5).xy; + return clip * viewport; +} + +vec4 +unproject (vec2 screen, float z, float w) +{ + vec2 clip = screen / viewport; + vec2 device = clip * 2.0 - 1.0; + return vec4 (device * w, z, w); +} + +vec2 +direction (vec2 from, vec2 to) +{ + vec2 t = to - from; + vec2 d = vec2 (0.0, 0.0); + + if (dot (t, t) > 0.001) { + d = normalize (t); + } + return d; +} + +vec2 +shared_direction (vec2 a, vec2 b) +{ + vec2 d = a + b; + + if (dot (d, d) > 0.001) { + d = normalize (d); + } else if (dot (a, a) > 0.001) { + d = normalize (a); + } else if (dot (b, b) > 0.001) { + d = normalize (b); + } else { + d = vec2 (0.0); + } + return d; +} + +float +estimateScale (vec3 position, vec2 sPosition, float width) +{ + vec4 view_pos = view_mat * vec4 (position, 1.0); + vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width, + 0.0, 0.0); + vec2 screen_scale_pos = project (projection_mat * scale_pos); + return distance (sPosition, screen_scale_pos); +} + +vec4 +transform (vec4 coord) +{ + return projection_mat * view_mat * vec4 (coord.xyz, 1.0); +} + +vec4 +curve_offset_vertex (vec4 last, vec4 current, vec4 next, float width) +{ + float offset = current.w; + + vec2 sLast = project (transform (last)); + vec2 sNext = project (transform (next)); + vec4 dCurrent = transform (current); + vec2 sCurrent = project (dCurrent); + + vec2 n1 = direction (sCurrent, sLast); + vec2 n2 = direction (sNext, sCurrent); + vec2 n = shared_direction (n1, n2); + + // rotate the normal by 90 degrees and scale by the desired offset + vec2 dir = vec2(n.y, -n.x) * offset; + float scale = estimateScale (vec3(current), sCurrent, width); + vec2 pos = sCurrent + dir * scale; + + return unproject (pos, dCurrent.z, dCurrent.w); +} + -- Fragment.fog uniform vec4 fog; @@ -587,8 +681,6 @@ attribute float texoff; attribute vec4 vcolora; attribute vec4 vcolorb; -uniform mat4 proj, view; -uniform vec2 viewport; uniform float width; varying vec2 texcoord; @@ -596,75 +688,15 @@ varying vec3 vbarycentric; varying vec4 colora; varying vec4 colorb; -vec4 -transform (vec3 coord) -{ - return proj * view * vec4 (coord, 1.0); -} - -vec2 -project (vec4 coord) -{ - vec3 device = coord.xyz / coord.w; - vec2 clip = (device * 0.5 + 0.5).xy; - return clip * viewport; -} - -vec4 -unproject (vec2 screen, float z, float w) -{ - vec2 clip = screen / viewport; - vec2 device = clip * 2.0 - 1.0; - return vec4 (device * w, z, w); -} - -float -estimateScale (vec3 position, vec2 sPosition) -{ - vec4 view_pos = view * vec4 (position, 1.0); - vec4 scale_pos = view_pos - vec4 (normalize (view_pos.xy) * width, - 0.0, 0.0); - vec2 screen_scale_pos = project (proj * scale_pos); - return distance (sPosition, screen_scale_pos); -} - void main (void) { - vec2 t, n1, n2, n; - vec2 sLast = project (transform (last.xyz)); - vec2 sNext = project (transform (next.xyz)); - vec4 dCurrent = transform (current.xyz); - vec2 sCurrent = project (dCurrent); - float off = current.w; - colora = vcolora; colorb = vcolorb; - texcoord = vec2 (texoff * 0.7, off);// * 0.5 + 0.5); + texcoord = vec2 (texoff * 0.7, current.w);// * 0.5 + 0.5); vbarycentric = barycentric; - t = sLast - sCurrent; - n1 = vec2 (0.0); - if (dot (t, t) > 0.001) - n1 = normalize (t); - t = sCurrent - sNext; - n2 = vec2 (0.0); - if (dot (t, t) > 0.001) - n2 = normalize (t); - n = vec2 (0.0); - if (n1 != -n2) - n = normalize (n1 + n2); - else if (dot (n1, n1) > 0.001) - n = n1; - else if (dot (n2, n2) > 0.001) - n = n2; - - // rotate the normal by 90 degrees and scale by the desired width - vec2 dir = vec2 (n.y, -n.x) * off; - float scale = estimateScale (current.xyz, sCurrent); - vec2 pos = sCurrent + dir * scale; - - gl_Position = unproject (pos, dCurrent.z, dCurrent.w); + gl_Position = curve_offset_vertex (last, current, next, width); } -- Fragment.particle.trail From c5731374cdc82ce956a7710be51a89146245d505 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Oct 2023 13:49:25 +0900 Subject: [PATCH 24/31] [glsl] Separate out the trails implementation This gets things *compiling* again, though it's still non-functional and definitely wrong (don't want trail in renderer_t), but I need to think about the design for getting trails as components. Also need to think about integrating trails into the client effects system so trails can be shared between renderers. --- include/QF/scene/entity.h | 1 + libs/video/renderer/Makemodule.am | 1 + libs/video/renderer/glsl/glsl_particles.c | 349 ---------------- libs/video/renderer/glsl/glsl_trails.c | 474 ++++++++++++++++++++++ 4 files changed, 476 insertions(+), 349 deletions(-) create mode 100644 libs/video/renderer/glsl/glsl_trails.c 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; +} From 5311f9906a279917b11cafdce1acd655155f7a61 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Oct 2023 14:26:54 +0900 Subject: [PATCH 25/31] [nq,qw] Call Mod_ClearAll in CL_Shutdown Although the model subsystem does this too, it does it too late relative to the video shutdown, resulting in segfaults for glsl due to the drivers having been unloaded. --- libs/models/model.c | 1 + nq/source/cl_main.c | 2 ++ qw/source/cl_main.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/libs/models/model.c b/libs/models/model.c index 3482fb5c1..c993fb154 100644 --- a/libs/models/model.c +++ b/libs/models/model.c @@ -161,6 +161,7 @@ mod_unload_model (size_t ind) //with alias models if (!mod->needload && mod->clear) { mod->clear (mod, mod->data); + mod->clear = 0; } if (mod->type != mod_alias) { mod->needload = true; diff --git a/nq/source/cl_main.c b/nq/source/cl_main.c index 22cce7e0a..f8f21c98b 100644 --- a/nq/source/cl_main.c +++ b/nq/source/cl_main.c @@ -216,6 +216,8 @@ static void CL_Shutdown (void *data) { CL_WriteConfiguration (); + + Mod_ClearAll (); } void diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index d1212bada..5f6287a82 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1440,6 +1440,8 @@ CL_Shutdown (void *data) dstring_delete (cls.downloadname); dstring_delete (cls.downloadurl); free (cl.players); + + Mod_ClearAll (); } void From 4554ea47b072f1fa94dd24bedab522a05579f909 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Oct 2023 15:05:13 +0900 Subject: [PATCH 26/31] [glsl] Apply an old debug stash for trails The code is mostly disabled, but this should prevent too much bitrot. --- libs/video/renderer/glsl/glsl_trails.c | 21 +++++++++++++++++---- libs/video/renderer/glsl/quakeforge.glsl | 12 ++++++++++-- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/libs/video/renderer/glsl/glsl_trails.c b/libs/video/renderer/glsl/glsl_trails.c index a3abeb34c..282a078fa 100644 --- a/libs/video/renderer/glsl/glsl_trails.c +++ b/libs/video/renderer/glsl/glsl_trails.c @@ -81,8 +81,15 @@ static const char *particle_trail_frag_effects[] = 0 }; +static const char *particle_trail_debug_frag_effects[] = +{ + "QuakeForge.Fragment.barycentric", + 0 +}; + static struct { int program; + int debug_program; shaderparam_t proj; shaderparam_t view; shaderparam_t viewport; @@ -95,7 +102,7 @@ static struct { shaderparam_t colora; shaderparam_t colorb; } trail = { - 0, + 0, 0, {"projection_mat", 1}, {"view_mat", 1}, {"viewport", 1}, @@ -199,15 +206,21 @@ glsl_R_ShutdownParticles (void) void glsl_R_InitParticles (void) { - shader_t *vert_shader, *frag_shader; + 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.program = GLSL_LinkProgram ("trail", vert, frag); + trail.debug_program = GLSL_LinkProgram ("trail.debug", vert, debug); + GLSL_ResolveShaderParam (trail.program, &trail.proj); GLSL_ResolveShaderParam (trail.program, &trail.view); GLSL_ResolveShaderParam (trail.program, &trail.viewport); @@ -254,7 +267,7 @@ new_trail_point (vec4f_t origin, float pscale, float percent) .p.vel = {}, .p.live = 2.0 - percent * 2.0, // .p.ramp = ramp,XXX - // .p.physics = R_ParticlePhysics ("pt_float"),XXX + // .p.physics = R_ParticlePhysics ("pt_float"),XXX pt_static for debug }; return point; @@ -310,7 +323,7 @@ set_vertex (trailvtx_t *v, const point_t *point, float w, const vec3_t bary, { VectorCopy (point->p.pos, v->vertex); VectorCopy (bary, v->bary); - v->vertex[3] = w * point->p.scale; + 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; diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index 0922eff30..384f10a33 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -728,18 +728,23 @@ main (void) //gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); vec3 tex3 = vec3 (texcoord, 0.5); float n = abs(snoise(tex3)); - float a = sqrt(1.0 - texcoord.y * texcoord.y); n += 0.5 * abs(snoise(tex3 * 2.0)); n += 0.25 * abs(snoise(tex3 * 4.0)); n += 0.125 * abs(snoise(tex3 * 8.0)); vec4 c = colora + colorb * n; +#if 1 + float a = sqrt(1.0 - texcoord.y * texcoord.y); c.a *= a; +#else + c.a *= 1.0 - exp (-2.0 * (1.0 - sqrt(texcoord.y * texcoord.y))); +#endif gl_FragColor = c; } -- Fragment.barycentric varying vec3 vbarycentric; +varying vec2 texcoord; float edgeFactor (void) @@ -752,7 +757,10 @@ edgeFactor (void) void main (void) { - gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); + //gl_FragColor = vec4 (vec3 (edgeFactor ()), 0.5); + vec4 c = vec4 (vec3 (edgeFactor ()), 0.5); + c.a *= 1.0 - exp (-4.0 * (1.0 - texcoord.y * texcoord.y)); + gl_FragColor = c; } -- version.130 #version 130 From a905dcd4f91d07e0b731403fd41c57d6acfe4844 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Oct 2023 18:37:59 +0900 Subject: [PATCH 27/31] [renderer] Update particle scale It seems I forgot this and didn't notice until now. The glsl renderer's particles (style 1) look a lot better now. --- libs/video/renderer/r_part.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/video/renderer/r_part.c b/libs/video/renderer/r_part.c index 0a73882e9..4227dd6ec 100644 --- a/libs/video/renderer/r_part.c +++ b/libs/video/renderer/r_part.c @@ -135,6 +135,7 @@ R_RunParticles (float dT) p->pos += dT * p->vel; p->vel += dT * (p->vel * parm->drag + gravity * parm->drag[3]); p->ramp += dT * parm->ramp; + p->scale += dT * parm->scale_rate; p->live -= dT; if (ramp) { p->icolor = ramp[(int)p->ramp]; From ef6b10afb170ad4a29759e764a395bc85b97e4a0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Oct 2023 21:27:04 +0900 Subject: [PATCH 28/31] [renderer] Remove dead r_part_comp.c --- libs/video/renderer/r_part_comp.c | 511 ------------------------------ 1 file changed, 511 deletions(-) delete mode 100644 libs/video/renderer/r_part_comp.c diff --git a/libs/video/renderer/r_part_comp.c b/libs/video/renderer/r_part_comp.c deleted file mode 100644 index a451d6459..000000000 --- a/libs/video/renderer/r_part_comp.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - r_part.c - - Interface for particles - - Copyright (C) 1996-1997 Id Software, Inc. - - 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 "QF/alloc.h" -#include "QF/cbuf.h" -#include "QF/cvar.h" -#include "QF/dstring.h" -#include "QF/hash.h" -#include "QF/qargs.h" -#include "QF/render.h" -#include "QF/script.h" -#include "QF/segtext.h" -#include "QF/sys.h" - -#include "compat.h" -#include "r_internal.h" - -typedef enum { - pt_phys_done, - pt_phys_add_vel, - pt_phys_sub_slowgrav, - pt_phys_add_grav, - pt_phys_sub_grav, - pt_phys_add_fastgrav, - pt_phys_add_ramp, // die - pt_phys_fade_alpha, // die - pt_phys_color_ramp1, - pt_phys_color_ramp2, - pt_phys_color_ramp3, - pt_phys_alpha_ramp, - pt_phys_explode_vel, - pt_phys_damp_vel, - pt_phys_grow_scale, - pt_phys_shrink_scale, // die - pt_phys_custom, // die -} pt_phys_e; - -typedef struct { - const char *name; - pt_phys_e opcode; - int num_params; -} pt_phys_opcode_t; - -typedef struct { - char *name; - qboolean (*func) (particle_t *part, void *data); - void *data; -} pt_phys_func_t; - -typedef union pt_phys_op_s { - int32_t op; - float parm; -} pt_phys_op_t; - -typedef struct pt_phys_script_s { - struct pt_phys_script_s *next; - char *name; - pt_phys_op_t *script; -} pt_phys_script_t; - -const char particle_types[] = -#include "particles.pc" -; - -static pt_phys_func_t *phys_funcs; -static int num_phys_funcs; -static int max_phys_funcs; -static pt_phys_script_t *phys_script_freelist; -static hashtab_t *phys_scripts; - -static pt_phys_opcode_t part_phys_opcodes[] = -{ - {"add_vel", pt_phys_add_vel, 0}, - {"sub_slowgrav", pt_phys_sub_slowgrav, 0}, - {"add_grav", pt_phys_add_grav, 0}, - {"sub_grav", pt_phys_sub_grav, 0}, - {"add_fastgrav", pt_phys_add_fastgrav, 0}, - {"add_ramp", pt_phys_add_ramp, 2}, - {"fade_alpha", pt_phys_fade_alpha, 1}, - {"color_ramp1", pt_phys_color_ramp1, 0}, - {"color_ramp2", pt_phys_color_ramp2, 0}, - {"color_ramp3", pt_phys_color_ramp3, 0}, - {"alpha_ramp", pt_phys_alpha_ramp, 1}, - {"explode_vel", pt_phys_explode_vel, 1}, - {"damp_vel", pt_phys_damp_vel, 1}, - {"grow_scale", pt_phys_grow_scale, 1}, - {"shrink_scale", pt_phys_shrink_scale, 1}, - - {0, pt_phys_done, 0}, -}; - -unsigned int r_maxparticles, numparticles; -particle_t *active_particles, *free_particles, *particles, **freeparticles; -vec3_t r_pright, r_pup, r_ppn; - -/* - R_MaxParticlesCheck - - Misty-chan: Dynamically change the maximum amount of particles on the fly. - Thanks to a LOT of help from Taniwha, Deek, Mercury, Lordhavoc, and lots of - others. -*/ -static void -R_MaxParticlesCheck (void) -{ - psystem_t *ps = &r_psystem;//FIXME - unsigned maxparticles = 0; - - maxparticles = r_particles ? r_particles_max : 0; - - if (ps->maxparticles == maxparticles) { - return; - } - - size_t size = sizeof (particle_t) + sizeof (partparm_t) - + sizeof (int *); - - if (ps->particles) { - Sys_Free (ps->particles, ps->maxparticles * size); - ps->particles = 0; - ps->partparams = 0; - ps->partramps = 0; - } - ps->maxparticles = maxparticles; - - if (ps->maxparticles) { - ps->particles = Sys_Alloc (ps->maxparticles * size); - ps->partparams = (partparm_t *) &ps->particles[ps->maxparticles]; - ps->partramps = (const int **) &ps->partparams[ps->maxparticles]; - } - R_ClearParticles (); -} - -void -R_ClearParticles (void) -{ - psystem_t *ps = &r_psystem;//FIXME - ps->numparticles = 0; -} - -void -R_RunParticles (float dT) -{ - psystem_t *ps = &r_psystem;//FIXME - vec4f_t gravity = ps->gravity; - - unsigned j = 0; - for (unsigned i = 0; i < ps->numparticles; i++) { - particle_t *p = &ps->particles[i]; - partparm_t *parm = &ps->partparams[i]; - - if (p->live <= 0 || p->ramp >= parm->ramp_max) { - continue; - } - const int *ramp = ps->partramps[i]; - if (i > j) { - ps->particles[j] = *p; - ps->partparams[j] = *parm; - ps->partramps[j] = ramp; - } - j += 1; - - p->pos += dT * p->vel; - p->vel += dT * (p->vel * parm->drag + gravity * parm->drag[3]); - p->ramp += dT * parm->ramp; - p->live -= dT; - if (ramp) { - p->icolor = ramp[(int)p->ramp]; - } - } - ps->numparticles = j; -} - -static inline qboolean -custom_func (particle_t *part, int op) -{ - int func; - func = op - pt_phys_custom; - if (func < 0 || func >= num_phys_funcs) { - Sys_Error ("invalid custom particle physics opcode: %d", op); - } - if (phys_funcs[func].func (part, phys_funcs[func].data)) { - part->die = -1; - return true; - } - return false; -} - -void -R_RunParticlePhysics (particle_t *part) -{ - const pt_phys_op_t *op; - float parm, max; - - if (!part->physics) { - // safety net for physicsless particles - add_ramp (part, 1, 4); - return; - } - for (op = part->physics; ; op++) { - if (op->op >= pt_phys_custom) { - if (custom_func (part, op->op)) - return; - } - - switch ((pt_phys_e) op->op) { - case pt_phys_done: - return; - case pt_phys_add_vel: - add_vel (part); - break; - case pt_phys_sub_slowgrav: - sub_slowgrav (part); - break; - case pt_phys_add_grav: - add_grav (part); - break; - case pt_phys_sub_grav: - sub_grav (part); - break; - case pt_phys_add_fastgrav: - add_fastgrav (part); - break; - case pt_phys_add_ramp: - parm = (++op)->parm; - max = (++op)->parm; - if (add_ramp (part, parm, max)) - return; - break; - case pt_phys_fade_alpha: - parm = (++op)->parm; - if (fade_alpha (part, parm)) - return; - break; - case pt_phys_color_ramp1: - part->color = ramp1[((int) part->ramp) % sizeof (ramp1)]; - break; - case pt_phys_color_ramp2: - part->color = ramp2[((int) part->ramp) % sizeof (ramp2)]; - break; - case pt_phys_color_ramp3: - part->color = ramp3[((int) part->ramp) % sizeof (ramp3)]; - break; - case pt_phys_alpha_ramp: - parm = (++op)->parm; - part->alpha = (parm - part->ramp) / parm; - break; - case pt_phys_explode_vel: - parm = (++op)->parm; - VectorMultAdd (part->vel, vr_data.frametime * parm, part->vel, - part->vel); - break; - case pt_phys_damp_vel: - parm = (++op)->parm; - part->vel[0] -= part->vel[0] * vr_data.frametime * parm; - part->vel[1] -= part->vel[1] * vr_data.frametime * parm; - break; - case pt_phys_grow_scale: - parm = (++op)->parm; - part->scale += vr_data.frametime * parm; - break; - case pt_phys_shrink_scale: - parm = (++op)->parm; - part->scale -= vr_data.frametime * parm; - if (part->scale <= 0.0) { - part->die = -1; - return; - } - break; - case pt_phys_custom: - // handled above - break; - } - } -} - -static pt_phys_opcode_t * -part_find_opcode (const char *name) -{ - pt_phys_opcode_t *op; - - for (op = part_phys_opcodes; op->name; op++) { - if (strcmp (op->name, name) == 0) - return op; - } - return 0; -} - -static pt_phys_func_t * -part_find_function (const char *name) -{ - pt_phys_func_t *func; - - //FIXME is a hash table worth it? - for (func = phys_funcs; func - phys_funcs < num_phys_funcs; func++) { - if (strcmp (func->name, name) == 0) - return func; - } - return 0; -} - -static void -part_add_op (dstring_t *phys, int op) -{ - int offs = phys->size; - phys->size += sizeof (pt_phys_op_t); - dstring_adjust (phys); - ((pt_phys_op_t *) (phys->str + offs))->op = op; -} - -static void -part_add_parm (dstring_t *phys, float parm) -{ - int offs = phys->size; - phys->size += sizeof (pt_phys_op_t); - dstring_adjust (phys); - ((pt_phys_op_t *) (phys->str + offs))->parm = parm; -} - -static pt_phys_script_t * -new_phys_script (void) -{ - pt_phys_script_t *phys_script; - ALLOC (16, pt_phys_script_t, phys_script, phys_script); - return phys_script; -} - -static void -free_phys_script (pt_phys_script_t *phys_script) -{ - FREE (phys_script, phys_script); -} - -static const char * -part_script_get_key (const void *_s, void *unused) -{ - const pt_phys_script_t *s = (const pt_phys_script_t *) _s; - return s->name; -} - -static void -part_script_free (void *_s, void *unused) -{ - pt_phys_script_t *s = (pt_phys_script_t *) _s; - free (s->name); - free (s->script); - free_phys_script (s); -} - -qboolean -R_CompileParticlePhysics (const char *name, const char *code) -{ - cbuf_args_t *args = Cbuf_ArgsNew (); - script_t *script = Script_New (); - pt_phys_opcode_t *opcode; - pt_phys_script_t *phys; - pt_phys_func_t *func; - dstring_t *phys_build = dstring_new (); - int i; - qboolean ret = false; - - if (!phys_scripts) { - phys_scripts = Hash_NewTable (61, part_script_get_key, - part_script_free, 0); - } - Script_Start (script, "name", code); - while (Script_GetToken (script, 1)) { - args->argc = 0; - Cbuf_ArgsAdd (args, Script_Token (script)); - while (Script_TokenAvailable (script, 0)) { - Script_GetToken (script, 0); - Cbuf_ArgsAdd (args, Script_Token (script)); - } - Sys_Printf ("%s:%d: %s\n", name, script->line, args->argv[0]->str); - if ((func = part_find_function (args->argv[0]->str))) { - if (args->argc > 1) { - Sys_Printf ("%s:%d: warning: ignoring extra args\n", - name, script->line); - } - part_add_op (phys_build, pt_phys_custom + (func - phys_funcs)); - } else if ((opcode = part_find_opcode (args->argv[0]->str))) { - part_add_op (phys_build, opcode->opcode); - if (args->argc - 1 > opcode->num_params) { - Sys_Printf ("%s:%d: warning: ignoring extra args\n", - name, script->line); - args->argc = opcode->num_params + 1; - } - for (i = 1; i < args->argc; i++) { - char *end; - float parm = strtof (args->argv[i]->str, &end); - if (end == args->argv[i]->str) { - Sys_Printf ("%s:%d: warning: bad float\n", - name, script->line); - } else if (*end) { - Sys_Printf ("%s:%d: warning: ignoring extra chars\n", - name, script->line); - } - part_add_parm (phys_build, parm); - } - if (args->argc - 1 > opcode->num_params) { - Sys_Printf ("%s:%d: warning: setting parms %d+ to zero\n", - name, script->line, args->argc - 1); - for (i--; i < opcode->num_params; i++) - part_add_parm (phys_build, 0); - } - } else { - Sys_Printf ("%s:%d: warning: unknown opcode/function: %s\n", - name, script->line, args->argv[0]->str); - } - } - if (phys_build->size) { - part_add_op (phys_build, pt_phys_done); - phys = new_phys_script (); - phys->name = strdup (name); - phys->script = (pt_phys_op_t *) dstring_freeze (phys_build); - Hash_Add (phys_scripts, phys); - ret = true; - } else { - dstring_delete (phys_build); - } - - Script_Delete (script); - Cbuf_ArgsDelete (args); - return ret; -} - -const pt_phys_op_t * -R_ParticlePhysics (const char *type) -{ - pt_phys_script_t *phys; - - if (!phys_scripts) - return 0; - if ((phys = Hash_Find (phys_scripts, type))) - return phys->script; - return 0; -} - -qboolean -R_AddParticlePhysicsFunction (const char *name, - qboolean (*func) (particle_t *part, void *data), - void *data) -{ - int i; - - for (i = 0; i < num_phys_funcs; i++) { - if (strcmp (name, phys_funcs[i].name) == 0) - return false; - } - if (num_phys_funcs == max_phys_funcs) { - max_phys_funcs += 16; - phys_funcs = realloc (phys_funcs, - max_phys_funcs * sizeof (pt_phys_func_t)); - if (!phys_funcs) { - Sys_Error ("R_AddParticlePhysicsFunction: out of memory"); - } - } - phys_funcs[num_phys_funcs].name = strdup (name); - phys_funcs[num_phys_funcs].func = func; - phys_funcs[num_phys_funcs].data = data; - return true; -} - -void -R_LoadParticles (void) -{ - segtext_t *text; - segchunk_t *chunk; - - text = Segtext_new (particle_types); - for (chunk = text->chunk_list; chunk; chunk = chunk->next) { - if (chunk->tag) { - Sys_Printf ("compiling %s\n", chunk->tag); - R_CompileParticlePhysics (chunk->tag, chunk->text); - } - } -} From 34daf9032d622e99bb8b767eb1cef6712dee3a46 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Oct 2023 10:31:12 +0900 Subject: [PATCH 29/31] [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. --- include/QF/GLSL/qf_particles.h | 4 + include/QF/plugin/vid_render.h | 2 + include/QF/render.h | 31 +- include/QF/scene/entity.h | 2 +- include/client/effects.h | 2 + include/r_dynamic.h | 15 +- include/r_internal.h | 3 +- libs/client/cl_effects.c | 52 +++ libs/video/renderer/Makemodule.am | 3 +- libs/video/renderer/glsl/glsl_main.c | 1 + libs/video/renderer/glsl/glsl_trails.c | 422 ++++++++----------------- libs/video/renderer/r_cvar.c | 1 + libs/video/renderer/r_init.c | 1 + libs/video/renderer/r_part.c | 1 - libs/video/renderer/r_screen.c | 3 + libs/video/renderer/r_trails.c | 219 +++++++++++++ libs/video/renderer/vid_render_glsl.c | 2 + nq/source/cl_main.c | 2 + qw/source/cl_main.c | 2 + 19 files changed, 463 insertions(+), 305 deletions(-) create mode 100644 libs/video/renderer/r_trails.c 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 (); From 43cea647094dc88639fd030352c4f71e2c3bcfaa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Oct 2023 13:11:40 +0900 Subject: [PATCH 30/31] [renderer] Get trails looking vaguely acceptable Still not great, but I like the falloff and the mixing is better. The path offset seems to be unstable, so that needs work still. --- libs/video/renderer/glsl/quakeforge.glsl | 10 ++-------- libs/video/renderer/r_trails.c | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/libs/video/renderer/glsl/quakeforge.glsl b/libs/video/renderer/glsl/quakeforge.glsl index 384f10a33..6673f3486 100644 --- a/libs/video/renderer/glsl/quakeforge.glsl +++ b/libs/video/renderer/glsl/quakeforge.glsl @@ -725,19 +725,13 @@ varying vec4 colorb; void main (void) { - //gl_FragColor = texture2D (smoke, texcoord) * vec4 (1.0, 1.0, 1.0, 0.7); vec3 tex3 = vec3 (texcoord, 0.5); float n = abs(snoise(tex3)); n += 0.5 * abs(snoise(tex3 * 2.0)); n += 0.25 * abs(snoise(tex3 * 4.0)); n += 0.125 * abs(snoise(tex3 * 8.0)); - vec4 c = colora + colorb * n; -#if 1 - float a = sqrt(1.0 - texcoord.y * texcoord.y); - c.a *= a; -#else - c.a *= 1.0 - exp (-2.0 * (1.0 - sqrt(texcoord.y * texcoord.y))); -#endif + vec4 c = mix (colora, colorb, n); + c.a *= exp (-4.0 * abs(texcoord.y)); gl_FragColor = c; } diff --git a/libs/video/renderer/r_trails.c b/libs/video/renderer/r_trails.c index 9d7255e76..c9b749814 100644 --- a/libs/video/renderer/r_trails.c +++ b/libs/video/renderer/r_trails.c @@ -114,8 +114,8 @@ R_Trail_Create (psystem_t *system, int num_points, vec4f_t start) auto p = trail_point_buffer + pointset.base + i; *p = (trailpnt_t) { .pos = start, - .colora = { 0xc0, 0xc0, 0xc0, 0xa0 }, - .colorb = { 0x40, 0x40, 0x40, 0x40 }, + .colora = { 0xc0, 0xa0, 0x60, 0x80 }, + .colorb = { 0x30, 0x30, 0x20, 0x00 }, .trailid = trail, .live = 10, }; @@ -144,7 +144,8 @@ R_Trail_Update (psystem_t *system, uint32_t trailid, vec4f_t pos) points[0].pos = points[2].pos + dist; points[1].pos = points[3].pos + dist; - if (dotf (dist, dist)[0] > 128) { + float len = sqrt (dotf (dist, dist)[0]); + if (len > 16) { for (uint32_t i = 4; i < p->count; i += 2) { vec4f_t t1 = points[i + 0].pos; vec4f_t t2 = points[i + 1].pos; @@ -152,6 +153,22 @@ R_Trail_Update (psystem_t *system, uint32_t trailid, vec4f_t pos) points[i + 1].pos = prev2; prev1 = t1; prev2 = t2; + + points[i + 0].pathoffset = len; + points[i + 1].pathoffset = len; + if (i < p->count - 2) { + dist = points[i + 2].pos - points[i + 0].pos; + len = sqrt (dotf (dist, dist)[0]); + } + } + } else { + for (uint32_t i = 4; i < p->count; i += 2) { + points[i + 0].pathoffset = len; + points[i + 1].pathoffset = len; + if (i < p->count - 2) { + dist = points[i + 2].pos - points[i + 0].pos; + len = sqrt (dotf (dist, dist)[0]); + } } } } From a8ff58baa4be16e1b118f3a501a1299471f51c92 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Oct 2023 17:30:28 +0900 Subject: [PATCH 31/31] [glsl] Remove a debug print --- libs/video/renderer/glsl/glsl_shader.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/video/renderer/glsl/glsl_shader.c b/libs/video/renderer/glsl/glsl_shader.c index 3f52def57..2098439ec 100644 --- a/libs/video/renderer/glsl/glsl_shader.c +++ b/libs/video/renderer/glsl/glsl_shader.c @@ -69,7 +69,6 @@ static void effect_free (void *e, void *unused) { glsl_effect_t *effect = e; - puts (effect->name); free ((char *) effect->name); Segtext_delete (effect->text); }