From: TimePath Date: Sat, 29 Aug 2015 05:26:23 +0000 (+1000) Subject: Polytrails! X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=ba3810740842d495073195bc5ea6afd1021cd617;p=xonotic%2Fxonotic-data.pk3dir.git Polytrails! --- diff --git a/gfx/trails/plain.tga b/gfx/trails/plain.tga new file mode 100644 index 000000000..3761275ad 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 index 000000000..22bd5fd8a --- /dev/null +++ b/qcsrc/client/mutators/all.inc @@ -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 index 000000000..14530a3c5 --- /dev/null +++ b/qcsrc/client/mutators/all.qc @@ -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 index 000000000..09c385e83 --- /dev/null +++ b/qcsrc/client/mutators/mutator/polytrails.qc @@ -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; +} diff --git a/qcsrc/client/progs.src b/qcsrc/client/progs.src index 506669602..5186dc150 100644 --- a/qcsrc/client/progs.src +++ b/qcsrc/client/progs.src @@ -34,6 +34,7 @@ view.qc wall.qc command/all.qc +mutators/all.qc weapons/projectile.qc // TODO diff --git a/qcsrc/common/physics.qc b/qcsrc/common/physics.qc index e5b83443f..b850864c8 100644 --- a/qcsrc/common/physics.qc +++ b/qcsrc/common/physics.qc @@ -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; diff --git a/qcsrc/lib/Math.qh b/qcsrc/lib/Math.qh index a8a52907a..bdf747429 100644 --- a/qcsrc/lib/Math.qh +++ b/qcsrc/lib/Math.qh @@ -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));