]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Polytrails!
authorTimePath <andrew.hardaker1995@gmail.com>
Sat, 29 Aug 2015 05:26:23 +0000 (15:26 +1000)
committerTimePath <andrew.hardaker1995@gmail.com>
Sat, 29 Aug 2015 05:28:46 +0000 (15:28 +1000)
gfx/trails/plain.tga [new file with mode: 0644]
qcsrc/client/mutators/all.inc [new file with mode: 0644]
qcsrc/client/mutators/all.qc [new file with mode: 0644]
qcsrc/client/mutators/mutator/polytrails.qc [new file with mode: 0644]
qcsrc/client/progs.src
qcsrc/common/physics.qc
qcsrc/lib/Math.qh

diff --git a/gfx/trails/plain.tga b/gfx/trails/plain.tga
new file mode 100644 (file)
index 0000000..3761275
Binary files /dev/null and b/gfx/trails/plain.tga differ
diff --git a/qcsrc/client/mutators/all.inc b/qcsrc/client/mutators/all.inc
new file mode 100644 (file)
index 0000000..22bd5fd
--- /dev/null
@@ -0,0 +1 @@
+#include "mutator/polytrails.qc"
diff --git a/qcsrc/client/mutators/all.qc b/qcsrc/client/mutators/all.qc
new file mode 100644 (file)
index 0000000..14530a3
--- /dev/null
@@ -0,0 +1 @@
+#include "all.inc"
diff --git a/qcsrc/client/mutators/mutator/polytrails.qc b/qcsrc/client/mutators/mutator/polytrails.qc
new file mode 100644 (file)
index 0000000..09c385e
--- /dev/null
@@ -0,0 +1,109 @@
+bool autocvar_cl_polytrails = false;
+float autocvar_cl_polytrail_segmentsize = 10;
+float autocvar_cl_polytrail_lifetime = .2;
+
+CLASS(PolyTrail, Object)
+    ATTRIB(PolyTrail, polytrail_follow, entity, NULL)
+    ATTRIB(PolyTrail, polytrail_tex, string, string_null)
+    /** Lifetime per segment */
+    ATTRIB(PolyTrail, polytrail_lifetime, float, autocvar_cl_polytrail_lifetime)
+    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)
+    /** 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)
+    #define POLYTRAIL_SEEK(_p, _rel) ((POLYTRAIL_BUFSIZE + (_p).polytrail_bufidx + (_rel)) % POLYTRAIL_BUFSIZE)
+
+    void Trail_draw();
+    ATTRIB(PolyTrail, draw, void(), Trail_draw)
+    void Trail_draw() {
+        PolyTrail this = self;
+        if (wasfreed(this.polytrail_follow)) this.polytrail_follow = NULL;
+        if (!this.polytrail_follow) {
+            float when = this.polytrail_buftime[this.polytrail_bufidx];
+            if (time - when > this.polytrail_lifetime) {
+                remove(this);
+                return;
+            }
+        } else {
+            setorigin(this, this.polytrail_follow.origin);
+            if (this.polytrail_cnt < 0 || vlen(this.origin - this.polytrail_bufpos[this.polytrail_bufidx]) >= autocvar_cl_polytrail_segmentsize) {
+                int i = POLYTRAIL_SEEK(this, 1);
+                this.polytrail_bufpos[i] = this.origin;
+                this.polytrail_buftime[i] = time;
+                this.polytrail_bufidx = i;
+                this.polytrail_cnt = bound(this.polytrail_cnt, i + 1, POLYTRAIL_BUFSIZE);
+            }
+        }
+
+        int count = this.polytrail_cnt;
+        for (int i = 0; i < count; ++i) {
+            int idx = POLYTRAIL_SEEK(this, -i);
+            float when = this.polytrail_buftime[idx];
+            if (time - when >= this.polytrail_lifetime) {
+                count = i + 1;
+                break;
+            }
+        }
+
+        vector from = this.origin;
+        for (int i = 0, n = count; i < n; ++i) {
+            int idx = POLYTRAIL_SEEK(this, -i);
+            float when = this.polytrail_buftime[idx];
+            vector to = this.polytrail_bufpos[idx];
+            // head: 0, tail: 1
+            float rtime = (time - when) / this.polytrail_lifetime;
+            noref float rdist = i / n;
+            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);
+            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;
+        }
+    }
+    CONSTRUCTOR(PolyTrail, entity _follow) {
+        CONSTRUCT(PolyTrail);
+        this.polytrail_follow = _follow;
+    }
+ENDCLASS(PolyTrail)
+
+REGISTER_MUTATOR(polytrails, true);
+
+MUTATOR_HOOKFUNCTION(polytrails, EditProjectile) {
+    return = false;
+    if (!autocvar_cl_polytrails) return;
+    PolyTrail t = NEW(PolyTrail, self);
+    t.polytrail_tex = "gfx/trails/plain.tga";
+    t.polytrail_rgb[0] = '1 0 0';
+    t.polytrail_rgb[1] = '0 1 0';
+    t.polytrail_rgb[2] = '0 0 1';
+    t.polytrail_alpha[0] = 1;
+    t.polytrail_alpha[1] = 0.5;
+    t.polytrail_alpha[2] = 0;
+    t.polytrail_thickness[0] = 10;
+    t.polytrail_thickness[1] = 5;
+    t.polytrail_thickness[2] = 0;
+}
index 5066696022308653a84774cbd84fc16494ef3d71..5186dc150dcd41acfcb7369299a532dff7566d6b 100644 (file)
@@ -34,6 +34,7 @@ view.qc
 wall.qc
 
 command/all.qc
+mutators/all.qc
 
 weapons/projectile.qc // TODO
 
index e5b83443fbcd3c28aecce9276cd006e5eead2e74..b850864c80028c82bf7ea3bdc0277a1f024867c4 100644 (file)
@@ -188,11 +188,11 @@ float IsMoveInDirection(vector mv, float ang) // key mix factor
        return ang > 1 ? 0 : ang < -1 ? 0 : 1 - fabs(ang);
 }
 
-float GeomLerp(float a, float lerp, float b)
+float GeomLerp(float a, float _lerp, float b)
 {
-       return a == 0 ? (lerp < 1 ? 0 : b)
-               : b == 0 ? (lerp > 0 ? 0 : a)
-               : a * pow(fabs(b / a), lerp);
+       return a == 0 ? (_lerp < 1 ? 0 : b)
+               : b == 0 ? (_lerp > 0 ? 0 : a)
+               : a * pow(fabs(b / a), _lerp);
 }
 
 noref float pmove_waterjumptime;
index a8a52907a6bc158e28fc45aa1d7a89719d2d09e1..bdf74742918ff5d4703d7bda8fef239213df1ede 100644 (file)
@@ -85,6 +85,24 @@ vector vsnap(vector point,float fsize)
     return vret;
 }
 
+float lerpratio(float f0, float f1, float ratio) { return f0 * (1 - ratio) + f1 * ratio; }
+
+float lerp(float t0, float f0, float t1, float f1, float t) { return lerpratio(f0, f1, (t - t0) / (t1 - t0)); }
+
+float lerp3ratio(float f0, float f1, float f2, float ratio)
+{
+       int mid = 0.5;
+       return ratio < mid ? lerpratio(f0, f1, ratio / mid) : ratio > mid ? lerpratio(f1, f2, (ratio - mid) / mid) : f1;
+}
+
+vector lerpvratio(vector f0, vector f1, float ratio) { return f0 * (1 - ratio) + f1 * ratio; }
+
+vector lerpv3ratio(vector f0, vector f1, vector f2, float ratio)
+{
+       int mid = 0.5;
+       return ratio < mid ? lerpvratio(f0, f1, ratio / mid) : ratio > mid ? lerpvratio(f1, f2, (ratio - mid) / mid) : f1;
+}
+
 vector lerpv(float t0, vector v0, float t1, vector v1, float t)
 {
        return v0 + (v1 - v0) * ((t - t0) / (t1 - t0));