From 63bc81b55d05a96bc96dd809134959bc4cba3ccd Mon Sep 17 00:00:00 2001 From: div0 Date: Tue, 26 Aug 2008 10:14:38 +0000 Subject: [PATCH] new particle property "movedir"; traces in that direction. Length of the vector is how much of trace_plane_normal to use. git-svn-id: svn://svn.icculus.org/nexuiz/trunk@4187 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/qcsrc/client/Main.qc | 1 + data/qcsrc/client/particles.qc | 15 +++- data/qcsrc/common/util.qc | 136 ++++++++++++++++++++++++++++++++ data/qcsrc/common/util.qh | 4 + data/qcsrc/server/g_triggers.qc | 5 +- data/qcsrc/server/g_world.qc | 2 + 6 files changed, 156 insertions(+), 7 deletions(-) diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 9a96e80f6..744cdb8ea 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -51,6 +51,7 @@ void CSQC_Init(void) CSQC_CheckEngine(); configdb = db_create(); + compressShortVector_init(); drawfont = 0; menu_visible = FALSE; diff --git a/data/qcsrc/client/particles.qc b/data/qcsrc/client/particles.qc index af024eb1c..ee2e1287f 100644 --- a/data/qcsrc/client/particles.qc +++ b/data/qcsrc/client/particles.qc @@ -43,6 +43,7 @@ float PointInBrush(entity brush, vector point) .float impulse; // density .string noise; // sound .float absolute; +.vector movedir; // trace direction void Draw_PointParticles() { @@ -62,7 +63,14 @@ void Draw_PointParticles() p_z += random() * sz_z; if(PointInBrush(self, p)) { - pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color); + if(self.movedir != '0 0 0') + { + traceline(p, p + normalize(self.movedir) * 4096, 0, world); + p = trace_endpos; + pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color); + } + else + pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color); if(self.noise != "") { self.origin = p; @@ -91,9 +99,8 @@ void Ent_PointParticles() self.impulse = ReadCoord(); // density (<0: point, >0: volume) if(self.impulse == 0) self.impulse = 1; // one per sec - self.velocity_x = ReadCoord(); - self.velocity_y = ReadCoord(); - self.velocity_z = ReadCoord(); + self.velocity = decompressShortVector(ReadShort()); + self.movedir = decompressShortVector(ReadShort()); self.waterlevel = ReadCoord(); self.count = ReadCoord(); self.glow_color = ReadByte(); diff --git a/data/qcsrc/common/util.qc b/data/qcsrc/common/util.qc index fe1a9d18f..fc912da86 100644 --- a/data/qcsrc/common/util.qc +++ b/data/qcsrc/common/util.qc @@ -476,3 +476,139 @@ vector cross(vector a, vector b) + '0 1 0' * (a_z * b_x - a_x * b_z) + '0 0 1' * (a_x * b_y - a_y * b_x); } + +// compressed vector format: +// like MD3, just even shorter +// 4 bit pitch (16 angles), 0 is -90, 8 is 0, 16 would be 90 +// 5 bit yaw (32 angles), 0=0, 8=90, 16=180, 24=270 +// 7 bit length (logarithmic encoding), 1/8 .. about 7844 +// length = 2^(length_encoded/8) / 8 +// if pitch is 90, yaw does nothing and therefore indicates the sign (yaw is then either 11111 or 11110); 11111 is pointing DOWN +// thus, valid values are from 0000.11110.0000000 to 1111.11111.1111111 +// the special value 0 indicates the zero vector + +float lengthLogTable[128]; + +float invertLengthLog(float x) +{ + float l, r, m, lerr, rerr; + + if(x >= lengthLogTable[127]) + return 127; + if(x <= lengthLogTable[0]) + return 0; + + l = 0; + r = 127; + + while(r - l > 1) + { + m = floor((l + r) / 2); + if(lengthLogTable[m] < x) + l = m; + else + r = m; + } + + // now: r is >=, l is < + lerr = (x - lengthLogTable[l]); + rerr = (lengthLogTable[r] - x); + if(lerr < rerr) + return l; + return r; +} + +vector decompressShortVector(float data) +{ + vector out; + float pitch, yaw, len; + if(data == 0) + return '0 0 0'; + pitch = (data & 0xF000) / 0x1000; + yaw = (data & 0x0F80) / 0x80; + len = (data & 0x007F); + + //print("\ndecompress: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n"); + + if(pitch == 0) + { + out_x = 0; + out_y = 0; + if(yaw == 31) + out_z = -1; + else + out_z = +1; + } + else + { + yaw = .19634954084936207740 * yaw; + pitch = .19634954084936207740 * pitch - 1.57079632679489661922; + out_x = cos(yaw) * cos(pitch); + out_y = sin(yaw) * cos(pitch); + out_z = -sin(pitch); + } + + //print("decompressed: ", vtos(out), "\n"); + + return out * lengthLogTable[len]; +} + +float compressShortVector(vector vec) +{ + vector ang; + float pitch, yaw, len; + if(vlen(vec) == 0) + return 0; + //print("compress: ", vtos(vec), "\n"); + ang = vectoangles(vec); + ang_x = -ang_x; + if(ang_x < -90) + ang_x += 360; + if(ang_x < -90 && ang_x > +90) + error("BOGUS vectoangles"); + //print("angles: ", vtos(ang), "\n"); + + pitch = floor(0.5 + (ang_x + 90) * 16 / 180) & 15; // -90..90 to 0..14 + if(pitch == 0) + { + if(vec_z < 0) + yaw = 31; + else + yaw = 30; + } + else + yaw = floor(0.5 + ang_y * 32 / 360) & 31; // 0..360 to 0..32 + len = invertLengthLog(vlen(vec)); + + //print("compressed: pitch ", ftos(pitch)); print("yaw ", ftos(yaw)); print("len ", ftos(len), "\n"); + + return (pitch * 0x1000) + (yaw * 0x80) + len; +} + +void compressShortVector_init() +{ + float l, f, i; + l = 1; + f = pow(2, 1/8); + for(i = 0; i < 128; ++i) + { + lengthLogTable[i] = l; + l *= f; + } + + if(cvar("developer")) + { + print("Verifying vector compression table...\n"); + for(i = 0x0F00; i < 0xFFFF; ++i) + if(i != compressShortVector(decompressShortVector(i))) + { + print("BROKEN vector compression: ", ftos(i)); + print(" -> ", vtos(decompressShortVector(i))); + print(" -> ", ftos(compressShortVector(decompressShortVector(i)))); + print("\n"); + error("b0rk"); + } + print("Done.\n"); + } +} + diff --git a/data/qcsrc/common/util.qh b/data/qcsrc/common/util.qh index faebcb762..e516b93bf 100644 --- a/data/qcsrc/common/util.qh +++ b/data/qcsrc/common/util.qh @@ -61,3 +61,7 @@ string mmsss(float t); string ScoreString(float vflags, float value); vector cross(vector a, vector b); + +void compressShortVector_init(); +vector decompressShortVector(float data); +float compressShortVector(vector vec); diff --git a/data/qcsrc/server/g_triggers.qc b/data/qcsrc/server/g_triggers.qc index 1547b7ab3..6fcbfd1de 100644 --- a/data/qcsrc/server/g_triggers.qc +++ b/data/qcsrc/server/g_triggers.qc @@ -501,9 +501,8 @@ float pointparticles_SendEntity(entity to) WriteCoord(MSG_ENTITY, self.maxs_z - self.mins_z); WriteShort(MSG_ENTITY, self.cnt); WriteCoord(MSG_ENTITY, self.impulse); - WriteCoord(MSG_ENTITY, self.velocity_x); - WriteCoord(MSG_ENTITY, self.velocity_y); - WriteCoord(MSG_ENTITY, self.velocity_z); + WriteShort(MSG_ENTITY, compressShortVector(self.velocity)); + WriteShort(MSG_ENTITY, compressShortVector(self.movedir)); WriteCoord(MSG_ENTITY, self.waterlevel); WriteCoord(MSG_ENTITY, self.count); WriteByte(MSG_ENTITY, self.glow_color); diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index 07e969d93..110ddd4bf 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -175,6 +175,8 @@ void spawnfunc_worldspawn (void) error("world already spawned - you may have EXACTLY ONE worldspawn!"); world_already_spawned = TRUE; + compressShortVector_init(); + local entity head; head = nextent(world); maxclients = 0; -- 2.39.2