]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Bring back polytrails implementation by TimePath with some fixes
authorMario <mario.mario@y7mail.com>
Tue, 12 Nov 2024 00:48:37 +0000 (10:48 +1000)
committerMario <mario.mario@y7mail.com>
Tue, 12 Nov 2024 00:48:37 +0000 (10:48 +1000)
qcsrc/client/_mod.inc
qcsrc/client/_mod.qh
qcsrc/client/polytrails.qc [new file with mode: 0644]
qcsrc/client/polytrails.qh [new file with mode: 0644]
qcsrc/client/weapons/projectile.qc
xonotic-client.cfg

index feb5497d110cbc92fcda8641cb26d7377f73adfa..d29d92b5642b6e9d70d1b3617ba7d41017575878 100644 (file)
@@ -6,6 +6,7 @@
 #include <client/main.qc>
 #include <client/mapvoting.qc>
 #include <client/player_skeleton.qc>
+#include <client/polytrails.qc>
 #include <client/shownames.qc>
 #include <client/teamradar.qc>
 #include <client/view.qc>
index 7ef159d6c5e2b49375402cc1cedf17d58eca460b..9203312dcfadb4faddeff4a5796bde1e0e0395f9 100644 (file)
@@ -6,6 +6,7 @@
 #include <client/main.qh>
 #include <client/mapvoting.qh>
 #include <client/player_skeleton.qh>
+#include <client/polytrails.qh>
 #include <client/shownames.qh>
 #include <client/teamradar.qh>
 #include <client/view.qh>
diff --git a/qcsrc/client/polytrails.qc b/qcsrc/client/polytrails.qc
new file mode 100644 (file)
index 0000000..6f40faa
--- /dev/null
@@ -0,0 +1,91 @@
+#include "polytrails.qh"
+
+#include <lib/warpzone/common.qh>
+
+#define POLYTRAIL_SEEK(_p, _rel) ((POLYTRAIL_BUFSIZE + (_p).polytrail_bufidx + (_rel)) % POLYTRAIL_BUFSIZE)
+void Trail_draw(entity this)
+{
+       if (wasfreed(this.polytrail_follow))
+               this.polytrail_follow = NULL;
+
+       // NOTE: need an internal reset distance for warpzones to work properly TODO?
+       float reset_distance = 200;
+
+       if (!this.polytrail_follow) {
+               float when = this.polytrail_buftime[this.polytrail_bufidx];
+               if (time - when > this.polytrail_lifetime) {
+                       delete(this);
+                       return;
+               }
+       } else if(reset_distance > 0 && this.polytrail_cnt > 0 && vdist(this.origin - this.polytrail_follow.origin, >, reset_distance)) {
+               Trail_recreate(this);
+       } else {
+               setorigin(this, this.polytrail_follow.origin);
+               if (this.polytrail_cnt < 0 || vdist(this.origin - this.polytrail_bufpos[this.polytrail_bufidx], >=, this.polytrail_segmentsize)) {
+                       int i = POLYTRAIL_SEEK(this, 1);
+                       this.polytrail_bufpos[i] = this.origin;
+                       float f = this.polytrail_noise;
+                       // TODO: alternate noise functions (none, chaotic, helix, zigzag, waves, ...)
+                       switch(this.polytrail_noisefunc)
+                       {
+                               default:
+                               case "none": this.polytrail_bufnoise[i] = '0 0 0'; break;
+                               case "chaotic": this.polytrail_bufnoise[i] = randompos(f * '-1 -1 -1', f * '1 1 1'); break;
+                       }
+                       this.polytrail_buftime[i] = time;
+                       this.polytrail_bufidx = i;
+                       this.polytrail_cnt = bound(this.polytrail_cnt, i + 1, POLYTRAIL_BUFSIZE);
+               }
+       }
+
+       vector from = this.origin;
+       int count = this.polytrail_cnt;
+       for (int i = 0; i < count; ++i) {
+               int idx = POLYTRAIL_SEEK(this, -i);
+               float when = this.polytrail_buftime[idx];
+               // head: 0, tail: 1
+               float rtime = (time - when) / this.polytrail_lifetime;
+               if (rtime >= 1) {
+                       break;
+               }
+               vector to = this.polytrail_bufpos[idx];
+               to += lerpvratio('0 0 0', this.polytrail_bufnoise[idx], rtime);
+               vector rgb = lerpv3ratio(this.polytrail_rgb[0], this.polytrail_rgb[1], this.polytrail_rgb[2], rtime);
+               float a = lerp3ratio(this.polytrail_alpha[0], this.polytrail_thickness[1], this.polytrail_alpha[2], rtime);
+               int thickness = lerp3ratio(this.polytrail_thickness[0], this.polytrail_thickness[1], this.polytrail_thickness[2], rtime);
+               vector thickdir = normalize(cross(normalize(to - from), view_origin - from)) * (thickness / 2);
+               vector A = from + thickdir;
+               vector B = from - thickdir;
+               vector C = to + thickdir;
+               vector D = to - thickdir;
+               R_BeginPolygon(this.polytrail_tex, DRAWFLAG_SCREEN, false);
+               R_PolygonVertex(B, '0 0 0', rgb, a);
+               R_PolygonVertex(A, '0 1 0', rgb, a);
+               R_PolygonVertex(C, '1 1 0', rgb, a);
+               R_PolygonVertex(D, '1 0 0', rgb, a);
+               R_EndPolygon();
+               from = to;
+       }
+}
+#undef POLYTRAIL_SEEK
+
+void Trail_recreate(entity this)
+{
+       PolyTrail t = NEW(PolyTrail, this.polytrail_follow);
+       t.polytrail_tex = this.polytrail_tex;
+       t.polytrail_rgb[0] = this.polytrail_rgb[0];
+       t.polytrail_rgb[1] = this.polytrail_rgb[1];
+       t.polytrail_rgb[2] = this.polytrail_rgb[2];
+       t.polytrail_alpha[0] = this.polytrail_alpha[0];
+       t.polytrail_alpha[1] = this.polytrail_alpha[1];
+       t.polytrail_alpha[2] = this.polytrail_alpha[2];
+       t.polytrail_thickness[0] = this.polytrail_thickness[0];
+       t.polytrail_thickness[1] = this.polytrail_thickness[1];
+       t.polytrail_thickness[2] = this.polytrail_thickness[2];
+       t.polytrail_lifetime = this.polytrail_lifetime;
+       t.polytrail_segmentsize = this.polytrail_segmentsize;
+       t.polytrail_noise = this.polytrail_noise;
+       t.polytrail_noisefunc = this.polytrail_noisefunc;
+
+       this.polytrail_follow = NULL;
+}
diff --git a/qcsrc/client/polytrails.qh b/qcsrc/client/polytrails.qh
new file mode 100644 (file)
index 0000000..4f59abf
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+bool autocvar_cl_polytrails = true;
+
+CLASS(PolyTrail, Object)
+       ATTRIB(PolyTrail, polytrail_follow, entity, NULL);
+       ATTRIB(PolyTrail, polytrail_tex, string, string_null);
+       /** Lifetime per segment */
+       ATTRIB(PolyTrail, polytrail_lifetime, float, 0.2);
+       ATTRIB(PolyTrail, polytrail_noise, float, 0);
+       ATTRIB(PolyTrail, polytrail_segmentsize, float, 10);
+       ATTRIB(PolyTrail, polytrail_noisefunc, string, "chaotic");
+       ATTRIBARRAY(PolyTrail, polytrail_rgb, vector, 3);
+       ATTRIBARRAY(PolyTrail, polytrail_alpha, float, 3);
+       ATTRIBARRAY(PolyTrail, polytrail_thickness, float, 3);
+
+       /**
+        * Increase as necessary if the buffer is overflowing
+        * symptom: tail of trail is wrong
+        * cause: projectiles are too fast for the segment size
+        */
+       const int POLYTRAIL_BUFSIZE = 1 << 7;
+       /** One or more positional points */
+       ATTRIBARRAY(PolyTrail, polytrail_bufpos, vector, POLYTRAIL_BUFSIZE);
+       /** Noise for ending position */
+       ATTRIBARRAY(PolyTrail, polytrail_bufnoise, vector, POLYTRAIL_BUFSIZE);
+       /** Time of input */
+       ATTRIBARRAY(PolyTrail, polytrail_buftime, float, POLYTRAIL_BUFSIZE);
+       /** Current read index */
+       ATTRIB(PolyTrail, polytrail_bufidx, float, -1);
+       /** Counts positions stored */
+       ATTRIB(PolyTrail, polytrail_cnt, float, 0);
+
+       void Trail_draw(entity this);
+       void Trail_recreate(entity this);
+       ATTRIB(PolyTrail, draw, void(entity this), Trail_draw);
+       CONSTRUCTOR(PolyTrail, entity _follow) {
+               CONSTRUCT(PolyTrail);
+               this.polytrail_follow = _follow;
+               IL_PUSH(g_drawables, this);
+       }
+ENDCLASS(PolyTrail)
index 893d53ae5a1cf3fd3c190ba6d725a6df7ea43fbb..d5f874150fd751e405944ba6e0cceeb6e1e40baf 100644 (file)
@@ -1,6 +1,7 @@
 #include "projectile.qh"
 
 #include <client/mutators/_mod.qh>
+#include <client/polytrails.qh>
 #include <common/constants.qh>
 #include <common/effects/all.qh>
 #include <common/effects/effect.qh>
@@ -360,6 +361,25 @@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
                                settouch(this, func_null);
                                this.bouncefactor = WEP_CVAR_SEC(WEP_ELECTRO, bouncefactor);
                                this.bouncestop = WEP_CVAR_SEC(WEP_ELECTRO, bouncestop);
+                               if(autocvar_cl_polytrails)
+                               {
+                                       this.traileffect = EFFECT_Null.m_id;
+                                       PolyTrail t = NEW(PolyTrail, this);
+                                       t.polytrail_tex = "particles/lgbeam.tga";
+                                       t.polytrail_rgb[0] = '0.8 0.8 1';
+                                       t.polytrail_rgb[1] = '0.5 0.5 1';
+                                       t.polytrail_rgb[2] = '0.1 0.1 0.7';
+                                       t.polytrail_alpha[0] = 1;
+                                       t.polytrail_alpha[1] = 0.5;
+                                       t.polytrail_alpha[2] = 0;
+                                       t.polytrail_thickness[0] = 15;
+                                       t.polytrail_thickness[1] = 7;
+                                       t.polytrail_thickness[2] = 0;
+                                       t.polytrail_lifetime = 0.18;
+                                       t.polytrail_segmentsize = 10;
+                                       t.polytrail_noise = 10;
+                                       t.polytrail_noisefunc = "chaotic";
+                               }
                                break;
                        case PROJECTILE_RPC:
                        case PROJECTILE_ROCKET:
@@ -408,6 +428,25 @@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
                        case PROJECTILE_CRYLINK_BOUNCING:
                                set_movetype(this, MOVETYPE_BOUNCE);
                                settouch(this, func_null);
+                               if(autocvar_cl_polytrails)
+                               {
+                                       this.traileffect = EFFECT_Null.m_id;
+                                       PolyTrail t = NEW(PolyTrail, this);
+                                       t.polytrail_tex = "gfx/crosshair_ring.tga"; // TODO: dedicated texture
+                                       t.polytrail_rgb[0] = '0.7 0 1';
+                                       t.polytrail_rgb[1] = '0.5 0 1';
+                                       t.polytrail_rgb[2] = '0.1 0 0.8';
+                                       t.polytrail_alpha[0] = 0.5;
+                                       t.polytrail_alpha[1] = 0.2;
+                                       t.polytrail_alpha[2] = 0;
+                                       t.polytrail_thickness[0] = 5;
+                                       t.polytrail_thickness[1] = 3;
+                                       t.polytrail_thickness[2] = 3;
+                                       t.polytrail_lifetime = 0.15;
+                                       t.polytrail_segmentsize = 80;
+                                       t.polytrail_noise = 0;
+                                       t.polytrail_noisefunc = "none";
+                               }
                                break;
                        case PROJECTILE_FIREBALL:
                                loopsound(this, CH_SHOTS_SINGLE, SND_FIREBALL_FLY2, VOL_BASE, ATTEN_NORM);
@@ -452,6 +491,48 @@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
                        case PROJECTILE_WAKIROCKET:
                                loopsound(this, CH_SHOTS_SINGLE, SND_TAG_ROCKET_FLY, VOL_BASE, ATTEN_NORM);
                                break;
+                       case PROJECTILE_ELECTRO_BEAM:
+                               if(autocvar_cl_polytrails)
+                               {
+                                       this.traileffect = EFFECT_Null.m_id;
+                                       PolyTrail t = NEW(PolyTrail, this);
+                                       t.polytrail_tex = "particles/lgbeam.tga";
+                                       t.polytrail_rgb[0] = '0.75 0.75 1';
+                                       t.polytrail_rgb[1] = '0.45 0.45 1';
+                                       t.polytrail_rgb[2] = '0.1 0.1 0.75';
+                                       t.polytrail_alpha[0] = 1;
+                                       t.polytrail_alpha[1] = 0.5;
+                                       t.polytrail_alpha[2] = 0;
+                                       t.polytrail_thickness[0] = 5;
+                                       t.polytrail_thickness[1] = 5;
+                                       t.polytrail_thickness[2] = 0;
+                                       t.polytrail_lifetime = 0.27;
+                                       t.polytrail_segmentsize = 10;
+                                       t.polytrail_noise = 5;
+                                       t.polytrail_noisefunc = "chaotic";
+                               }
+                               break;
+                       case PROJECTILE_CRYLINK:
+                               if(autocvar_cl_polytrails)
+                               {
+                                       this.traileffect = EFFECT_Null.m_id;
+                                       PolyTrail t = NEW(PolyTrail, this);
+                                       t.polytrail_tex = "gfx/crosshair_ring.tga"; // TODO: dedicated texture
+                                       t.polytrail_rgb[0] = '0.7 0 1';
+                                       t.polytrail_rgb[1] = '0.5 0 1';
+                                       t.polytrail_rgb[2] = '0.1 0 0.8';
+                                       t.polytrail_alpha[0] = 0.75;
+                                       t.polytrail_alpha[1] = 0.2;
+                                       t.polytrail_alpha[2] = 0;
+                                       t.polytrail_thickness[0] = 5;
+                                       t.polytrail_thickness[1] = 3;
+                                       t.polytrail_thickness[2] = 3;
+                                       t.polytrail_lifetime = 0.15;
+                                       t.polytrail_segmentsize = 80;
+                                       t.polytrail_noise = 0;
+                                       t.polytrail_noisefunc = "none";
+                               }
+                               break;
                        /*
                        case PROJECTILE_WAKICANNON:
                            break;
index 332c4b74198d0feb71bc050d75d4bf56561359cc..8cd277a9b9b40c4d48afcbcf0bb0bcdd7f5c3a30 100644 (file)
@@ -951,3 +951,5 @@ set menu_reverted_nonsaved_cvars "" "These cvars are currently marked as saved i
 
 // Avoid perf problems near '0 0 0'; `set` without a description is because only current DP has this engine cvar
 set cl_areagrid_link_SOLID_NOT 0
+
+seta cl_polytrails 1 "enable polygon-based trail effect drawing (looks better but may impact performance)"