support for roll/pitch on model ellipse collision

master
Lee Salzman 2013-06-04 21:41:55 +03:00
parent 63fb76d25b
commit 5bb0779a7a
4 changed files with 226 additions and 189 deletions

View File

@ -282,27 +282,21 @@ bool mmintersect(const extentity &e, const vec &o, const vec &ray, float maxdist
int yaw = e.attr2, pitch = e.attr3, roll = e.attr4;
if(yaw != 0)
{
if(yaw < 0) yaw = 360 + yaw%360;
else if(yaw >= 360) yaw %= 360;
const vec2 &rot = sincos360[yaw];
mo.rotate_around_z(rot.x, -rot.y);
mray.rotate_around_z(rot.x, -rot.y);
const vec2 &rot = sincosmod360(-yaw);
mo.rotate_around_z(rot);
mray.rotate_around_z(rot);
}
if(pitch != 0)
{
if(pitch < 0) pitch = 360 + pitch%360;
else if(pitch >= 360) pitch %= 360;
const vec2 &rot = sincos360[pitch];
mo.rotate_around_x(rot.x, -rot.y);
mray.rotate_around_x(rot.x, -rot.y);
const vec2 &rot = sincosmod360(-pitch);
mo.rotate_around_x(rot);
mray.rotate_around_x(rot);
}
if(roll != 0)
{
if(roll < 0) roll = 360 + roll%360;
else if(roll >= 360) roll %= 360;
const vec2 &rot = sincos360[roll];
mo.rotate_around_y(rot.x, rot.y);
mray.rotate_around_y(rot.x, rot.y);
const vec2 &rot = sincosmod360(roll);
mo.rotate_around_y(rot);
mray.rotate_around_y(rot);
}
if(m->bih->traverse(mo, mray, maxdist ? maxdist : 1e16f, dist, mode))
{

View File

@ -82,17 +82,17 @@ namespace mpr
struct EntOBB
{
physent *ent;
quat orient;
matrix3x3 orient;
float zmargin;
EntOBB(physent *ent, float zmargin = 0) : ent(ent), orient(vec(0, 0, 1), ent->yaw*RAD), zmargin(zmargin) {}
EntOBB(physent *ent, float zmargin = 0) : ent(ent), orient(ent->yaw*RAD, vec(0, 0, 1)), zmargin(zmargin) {}
vec center() const { vec o(ent->o); o.z += (ent->aboveeye - ent->eyeheight - zmargin)/2; return o; }
vec contactface(const vec &wn, const vec &wdir) const
{
vec n = orient.invertedrotate(wn).div(vec(ent->xradius, ent->yradius, (ent->aboveeye + ent->eyeheight + zmargin)/2)),
dir = orient.invertedrotate(wdir),
vec n = orient.transform(wn).div(vec(ent->xradius, ent->yradius, (ent->aboveeye + ent->eyeheight + zmargin)/2)),
dir = orient.transform(wdir),
an(fabs(n.x), fabs(n.y), dir.z ? fabs(n.z) : 0),
fn(0, 0, 0);
if(an.x > an.y)
@ -102,19 +102,19 @@ namespace mpr
}
else if(an.y > an.z) fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
return orient.rotate(fn);
return orient.transposedtransform(fn);
}
vec supportpoint(const vec &n) const
{
vec ln = orient.invertedrotate(n), p(0, 0, 0);
vec ln = orient.transform(n), p(0, 0, 0);
if(ln.x > 0) p.x += ent->xradius;
else p.x -= ent->xradius;
if(ln.y > 0) p.y += ent->yradius;
else p.y -= ent->yradius;
if(ln.z > 0) p.z += ent->aboveeye;
else p.z -= ent->eyeheight + zmargin;
return orient.rotate(p).add(ent->o);
return orient.transposedtransform(p).add(ent->o);
}
};
@ -195,20 +195,22 @@ namespace mpr
struct ModelOBB
{
vec o, radius;
quat orient;
matrix3x3 orient;
ModelOBB(const vec &ent, const vec &center, const vec &radius, float yaw, float pitch, float roll) : o(ent), radius(radius), orient(vec(0, 0, 1), yaw*RAD)
ModelOBB(const vec &ent, const vec &center, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
{
if(pitch) orient.mul(quat(vec(1, 0, 0), pitch*RAD));
if(roll) orient.mul(quat(vec(0, -1, 0), roll*RAD));
o.add(orient.rotate(center));
orient.identity();
if(roll) orient.rotate_around_y(sincosmod360(roll));
if(pitch) orient.rotate_around_x(sincosmod360(-pitch));
if(yaw) orient.rotate_around_z(sincosmod360(-yaw));
o.add(orient.transposedtransform(center));
}
vec center() const { return o; }
vec contactface(const vec &wn, const vec &wdir) const
{
vec n = orient.invertedrotate(wn).div(radius), dir = orient.invertedrotate(wdir),
vec n = orient.transform(wn).div(radius), dir = orient.transform(wdir),
an(fabs(n.x), fabs(n.y), dir.z ? fabs(n.z) : 0),
fn(0, 0, 0);
if(an.x > an.y)
@ -218,63 +220,65 @@ namespace mpr
}
else if(an.y > an.z) fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
else if(an.z > 0) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
return orient.rotate(fn);
return orient.transposedtransform(fn);
}
vec supportpoint(const vec &n) const
{
vec ln = orient.invertedrotate(n), p(0, 0, 0);
vec ln = orient.transform(n), p(0, 0, 0);
if(ln.x > 0) p.x += radius.x;
else p.x -= radius.x;
if(ln.y > 0) p.y += radius.y;
else p.y -= radius.y;
if(ln.z > 0) p.z += radius.z;
else p.z -= radius.z;
return orient.rotate(p).add(o);
return orient.transposedtransform(p).add(o);
}
};
struct ModelEllipse
{
vec o, radius;
quat orient;
matrix3x3 orient;
ModelEllipse(const vec &ent, const vec &center, const vec &radius, float yaw, float pitch, float roll) : o(ent), radius(radius), orient(vec(0, 0, 1), yaw*RAD)
ModelEllipse(const vec &ent, const vec &center, const vec &radius, float yaw, float pitch, float roll) : o(ent), radius(radius)
{
if(pitch) orient.mul(quat(vec(1, 0, 0), pitch*RAD));
if(roll) orient.mul(quat(vec(0, -1, 0), roll*RAD));
o.add(orient.rotate(center));
orient.identity();
if(roll) orient.rotate_around_y(sincosmod360(roll));
if(pitch) orient.rotate_around_x(sincosmod360(-pitch));
if(yaw) orient.rotate_around_z(sincosmod360(-yaw));
o.add(orient.transposedtransform(center));
}
vec center() const { return o; }
vec contactface(const vec &wn, const vec &wdir) const
{
vec n = orient.invertedrotate(wn).div(radius), dir = orient.invertedrotate(wdir);
vec n = orient.transform(wn).div(radius), dir = orient.transform(wdir);
float dxy = n.dot2(n), dz = n.z*n.z;
vec fn(0, 0, 0);
if(dz > dxy && dir.z) fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
else if(n.dot2(dir) < 0)
{
fn.x = n.x*radius.x;
fn.y = n.y*radius.y;
fn.x = n.x*radius.y;
fn.y = n.y*radius.x;
fn.normalize();
}
return orient.rotate(fn);
return orient.transposedtransform(fn);
}
vec supportpoint(const vec &n) const
{
vec ln = orient.invertedrotate(n), p(0, 0, 0);
vec ln = orient.transform(n), p(0, 0, 0);
if(ln.z > 0) p.z += radius.z;
else p.z -= radius.z;
if(ln.x || ln.y)
{
float r = n.magnitude2();
float r = ln.magnitude2();
p.x += ln.x*radius.x/r;
p.y += ln.y*radius.y/r;
}
return orient.rotate(p).add(o);
return orient.transposedtransform(p).add(o);
}
};

View File

@ -717,36 +717,13 @@ bool plcollide(physent *d, const vec &dir) // collide with player or monster
void rotatebb(vec &center, vec &radius, int yaw, int pitch, int roll)
{
if(roll)
{
if(roll < 0) roll = 360 + roll%360;
else if(roll >= 360) roll %= 360;
const vec2 &rot = sincos360[roll];
center.rotate_around_y(rot.x, -rot.y);
vec2 oldradius(radius.x, radius.z);
radius.x = fabs(oldradius.x*rot.x) + fabs(oldradius.y*rot.y);
radius.z = fabs(oldradius.y*rot.x) + fabs(oldradius.x*rot.y);
}
if(pitch)
{
if(pitch < 0) pitch = 360 + pitch%360;
else if(pitch >= 360) pitch %= 360;
const vec2 &rot = sincos360[pitch];
center.rotate_around_x(rot.x, rot.y);
vec2 oldradius(radius.y, radius.z);
radius.y = fabs(oldradius.x*rot.x) + fabs(oldradius.y*rot.y);
radius.z = fabs(oldradius.y*rot.x) + fabs(oldradius.x*rot.y);
}
if(yaw)
{
if(yaw < 0) yaw = 360 + yaw%360;
else if(yaw >= 360) yaw %= 360;
const vec2 &rot = sincos360[yaw];
center.rotate_around_z(rot.x, rot.y);
vec2 oldradius(radius);
radius.x = fabs(oldradius.x*rot.x) + fabs(oldradius.y*rot.y);
radius.y = fabs(oldradius.y*rot.x) + fabs(oldradius.x*rot.y);
}
matrix3x3 orient;
orient.identity();
if(yaw) orient.rotate_around_z(sincosmod360(yaw));
if(pitch) orient.rotate_around_x(sincosmod360(pitch));
if(roll) orient.rotate_around_y(sincosmod360(-roll));
center = orient.transform(center);
radius = orient.abstransform(radius);
}
template<class E, class M>
@ -768,37 +745,13 @@ static inline bool mmcollide(physent *d, const vec &dir, const extentity &e, con
template<class E>
static bool fuzzycolliderect(physent *d, const vec &dir, float cutoff, const vec &o, const vec &center, const vec &radius, int yaw, int pitch, int roll)
{
vec bbcenter = center, bbradius = radius;
rotatebb(bbcenter, bbradius, yaw, pitch, roll);
bbcenter.add(o);
mpr::ModelOBB mdlvol(o, center, radius, yaw, pitch, roll);
vec bbradius = mdlvol.orient.abstransposedtransform(radius);
if(fabs(d->o.x - bbcenter.x) > bbradius.x + d->radius || fabs(d->o.y - bbcenter.y) > bbradius.y + d->radius ||
d->o.z + d->aboveeye < bbcenter.z - bbradius.z || d->o.z - d->eyeheight > bbcenter.z + bbradius.z)
if(fabs(d->o.x - mdlvol.o.x) > bbradius.x + d->radius || fabs(d->o.y - mdlvol.o.y) > bbradius.y + d->radius ||
d->o.z + d->aboveeye < mdlvol.o.z - bbradius.z || d->o.z - d->eyeheight > mdlvol.o.z + bbradius.z)
return true;
matrix3x3 orient;
orient.identity();
if(roll)
{
if(roll < 0) roll = 360 + roll%360;
else if(roll >= 360) roll %= 360;
const vec2 &rot = sincos360[roll];
orient.rotate_around_y(rot.x, rot.y);
}
if(pitch)
{
if(pitch < 0) pitch = 360 + pitch%360;
else if(pitch >= 360) pitch %= 360;
const vec2 &rot = sincos360[pitch];
orient.rotate_around_x(rot.x, -rot.y);
}
if(yaw)
{
if(yaw < 0) yaw = 360 + yaw%360;
else if(yaw >= 360) yaw %= 360;
const vec2 &rot = sincos360[yaw];
orient.rotate_around_z(rot.x, -rot.y);
}
E entvol(d);
wall = vec(0, 0, 0);
float bestdist = -1e10f;
@ -808,15 +761,15 @@ static bool fuzzycolliderect(physent *d, const vec &dir, float cutoff, const vec
float dist;
switch(i)
{
case 0: w = vec(orient.a).neg(); dist = center.x - radius.x; break;
case 1: w = orient.a; dist = -center.x - radius.x; break;
case 2: w = vec(orient.b).neg(); dist = center.y - radius.y; break;
case 3: w = orient.b; dist = -center.y - radius.y; break;
case 4: w = vec(orient.c).neg(); dist = center.z - radius.z; break;
case 5: w = orient.c; dist = -center.z - radius.z; break;
case 0: w = vec(mdlvol.orient.a).neg(); dist = -radius.x; break;
case 1: w = mdlvol.orient.a; dist = -radius.x; break;
case 2: w = vec(mdlvol.orient.b).neg(); dist = -radius.y; break;
case 3: w = mdlvol.orient.b; dist = -radius.y; break;
case 4: w = vec(mdlvol.orient.c).neg(); dist = -radius.z; break;
case 5: w = mdlvol.orient.c; dist = -radius.z; break;
}
vec pw = entvol.supportpoint(vec(w).neg());
dist += w.dot(vec(pw).sub(o));
dist += w.dot(vec(pw).sub(mdlvol.o));
if(dist >= 0) return true;
if(dist <= bestdist) continue;
wall = vec(0, 0, 0);
@ -840,6 +793,58 @@ static bool fuzzycolliderect(physent *d, const vec &dir, float cutoff, const vec
return false;
}
template<class E>
static bool fuzzycollideellipse(physent *d, const vec &dir, float cutoff, const vec &o, const vec &center, const vec &radius, int yaw, int pitch, int roll)
{
E entvol(d);
mpr::ModelEllipse mdlvol(o, center, radius, yaw, pitch, roll);
if(!mpr::collide(entvol, mdlvol)) return true;
wall = vec(0, 0, 0);
float bestdist = -1e10f;
loopi(3)
{
vec w;
float dist;
switch(i)
{
case 0: w = mdlvol.orient.c; dist = -radius.z; break;
case 1: w = vec(mdlvol.orient.c).neg(); dist = -radius.z; break;
case 2:
{
vec2 ln(mdlvol.orient.transform(entvol.center().sub(mdlvol.o)));
float r = ln.magnitude();
if(r < 1e-6f) continue;
vec2 lw = vec2(ln.x*radius.y, ln.y*radius.x).normalize();
w = mdlvol.orient.transposedtransform(lw);
dist = -vec2(ln.x*radius.x, ln.y*radius.y).dot(lw)/r;
break;
}
}
vec pw = entvol.supportpoint(vec(w).neg());
dist += w.dot(vec(pw).sub(mdlvol.o));
if(dist <= bestdist) continue;
wall = vec(0, 0, 0);
bestdist = dist;
if(!dir.iszero())
{
if(w.dot(dir) >= -cutoff*dir.magnitude()) continue;
if(d->type<ENT_CAMERA &&
dist < (dir.z*w.z < 0 ?
d->zmargin-(d->eyeheight+d->aboveeye)/(dir.z < 0 ? 3.0f : 4.0f) :
((dir.x*w.x < 0 || dir.y*w.y < 0) ? -d->radius : 0)))
continue;
}
wall = w;
}
if(wall.iszero())
{
inside = true;
return true;
}
return false;
}
bool mmcollide(physent *d, const vec &dir, float cutoff, octaentities &oc) // collide with a mapmodel
{
const vector<extentity *> &ents = entities::getents();
@ -859,8 +864,11 @@ bool mmcollide(physent *d, const vec &dir, float cutoff, octaentities &oc) // co
if(m->ellipsecollide)
{
//if(!mmcollide<mpr::EntCylinder, mpr::ModelEllipse>(d, dir, e, center, radius, yaw, pitch, roll)) return false;
if(pitch || roll) rotatebb(center, radius, 0, pitch, roll);
if(!ellipsecollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return false;
if(pitch || roll)
{
if(!fuzzycollideellipse<mpr::EntCapsule>(d, dir, cutoff, e.o, center, radius, yaw, pitch, roll)) return false;
}
else if(!ellipsecollide(d, dir, e.o, center, yaw, radius.x, radius.y, radius.z, radius.z)) return false;
}
//else if(!mmcollide<mpr::EntCylinder, mpr::ModelOBB>(d, dir, e, center, radius, yaw, pitch, roll)) return false;
else if(pitch || roll)

View File

@ -1,5 +1,59 @@
struct vec;
struct vec4;
struct vec2;
struct vec2
{
union
{
struct { float x, y; };
float v[2];
};
vec2() {}
vec2(float x, float y) : x(x), y(y) {}
explicit vec2(const vec &v);
explicit vec2(const vec4 &v);
float &operator[](int i) { return v[i]; }
float operator[](int i) const { return v[i]; }
bool operator==(const vec2 &o) const { return x == o.x && y == o.y; }
bool operator!=(const vec2 &o) const { return x != o.x || y != o.y; }
bool iszero() const { return x==0 && y==0; }
float dot(const vec2 &o) const { return x*o.x + y*o.y; }
float squaredlen() const { return dot(*this); }
float magnitude() const { return sqrtf(squaredlen()); }
vec2 &normalize() { mul(1/magnitude()); return *this; }
float cross(const vec2 &o) const { return x*o.y - y*o.x; }
vec2 &mul(float f) { x *= f; y *= f; return *this; }
vec2 &mul(const vec2 &o) { x *= o.x; y *= o.y; return *this; }
vec2 &div(float f) { x /= f; y /= f; return *this; }
vec2 &div(const vec2 &o) { x /= o.x; y /= o.y; return *this; }
vec2 &add(float f) { x += f; y += f; return *this; }
vec2 &add(const vec2 &o) { x += o.x; y += o.y; return *this; }
vec2 &sub(float f) { x -= f; y -= f; return *this; }
vec2 &sub(const vec2 &o) { x -= o.x; y -= o.y; return *this; }
vec2 &neg() { x = -x; y = -y; return *this; }
vec2 &lerp(const vec2 &b, float t) { x += (b.x-x)*t; y += (b.y-y)*t; return *this; }
vec2 &lerp(const vec2 &a, const vec2 &b, float t) { x = a.x + (b.x-a.x)*t; y = a.y + (b.y-a.y)*t; return *this; }
vec2 &avg(const vec2 &b) { add(b); mul(0.5f); return *this; }
};
static inline bool htcmp(const vec2 &x, const vec2 &y)
{
return x == y;
}
static inline uint hthash(const vec2 &k)
{
union { uint i; float f; } x, y;
x.f = k.x; y.f = k.y;
uint v = x.i^y.i;
return v + (v>>12);
}
struct vec
{
@ -16,8 +70,8 @@ struct vec
vec(float a, float b, float c) : x(a), y(b), z(c) {}
explicit vec(int v[3]) : x(v[0]), y(v[1]), z(v[2]) {}
explicit vec(const float *v) : x(v[0]), y(v[1]), z(v[2]) {}
explicit vec(const vec2 &v, float z = 0) : x(v.x), y(v.y), z(z) {}
explicit vec(const vec4 &v);
explicit vec(const vec2 &v, float z = 0);
vec(float yaw, float pitch) : x(-sinf(yaw)*cosf(pitch)), y(cosf(yaw)*cosf(pitch)), z(sinf(pitch)) {}
@ -31,8 +85,10 @@ struct vec
bool iszero() const { return x==0 && y==0 && z==0; }
float squaredlen() const { return x*x + y*y + z*z; }
float dot2(const vec2 &o) const { return x*o.x + y*o.y; }
float dot2(const vec &o) const { return x*o.x + y*o.y; }
float dot(const vec &o) const { return x*o.x + y*o.y + z*o.z; }
float absdot(const vec &o) const { return fabs(x*o.x) + fabs(y*o.y) + fabs(z*o.z); }
vec &mul(const vec &o) { x *= o.x; y *= o.y; z *= o.z; return *this; }
vec &mul(float f) { x *= f; y *= f; z *= f; return *this; }
vec &div(const vec &o) { x /= o.x; y /= o.y; z /= o.z; return *this; }
@ -47,6 +103,7 @@ struct vec
vec &max(const vec &o) { x = ::max(x, o.x); y = ::max(y, o.y); z = ::max(z, o.z); return *this; }
vec &min(float f) { x = ::min(x, f); y = ::min(y, f); z = ::min(z, f); return *this; }
vec &max(float f) { x = ::max(x, f); y = ::max(y, f); z = ::max(z, f); return *this; }
vec &abs() { x = fabs(x); y = fabs(y); z = fabs(z); return *this; }
vec &clamp(float f, float h) { x = ::clamp(x, f, h); y = ::clamp(y, f, h); z = ::clamp(z, f, h); return *this; }
float magnitude2() const { return sqrtf(dot2(*this)); }
float magnitude() const { return sqrtf(squaredlen()); }
@ -98,11 +155,9 @@ struct vec
vec &rotate_around_x(float angle) { return rotate_around_x(cosf(angle), sinf(angle)); }
vec &rotate_around_y(float angle) { return rotate_around_y(cosf(angle), sinf(angle)); }
vec &rotate(float angle, const vec &d)
{
float c = cosf(angle), s = sinf(angle);
return rotate(c, s, d);
}
vec &rotate_around_z(const vec2 &sc) { return rotate_around_z(sc.x, sc.y); }
vec &rotate_around_x(const vec2 &sc) { return rotate_around_x(sc.x, sc.y); }
vec &rotate_around_y(const vec2 &sc) { return rotate_around_y(sc.x, sc.y); }
vec &rotate(float c, float s, const vec &d)
{
@ -112,6 +167,9 @@ struct vec
return *this;
}
vec &rotate(float angle, const vec &d) { return rotate(cosf(angle), sinf(angle), d); }
vec &rotate(const vec2 &sc, const vec &d) { return rotate(sc.x, sc.y, d); }
void orthogonal(const vec &d)
{
int i = fabs(d.x) > fabs(d.y) ? (fabs(d.x) > fabs(d.z) ? 0 : 2) : (fabs(d.y) > fabs(d.z) ? 1 : 2);
@ -156,6 +214,8 @@ struct vec
int tohexcolor() { return ((int(r*255)>>16)&0xFF)|((int(g*255)>>8)&0xFF)|(int(b*255)&0xFF); }
};
inline vec2::vec2(const vec &v) : x(v.x), y(v.y) {}
static inline bool htcmp(const vec &x, const vec &y)
{
return x == y;
@ -242,66 +302,15 @@ struct vec4
vec4 &rotate_around_z(float angle) { return rotate_around_z(cosf(angle), sinf(angle)); }
vec4 &rotate_around_x(float angle) { return rotate_around_x(cosf(angle), sinf(angle)); }
vec4 &rotate_around_y(float angle) { return rotate_around_y(cosf(angle), sinf(angle)); }
vec4 &rotate_around_z(const vec2 &sc) { return rotate_around_z(sc.x, sc.y); }
vec4 &rotate_around_x(const vec2 &sc) { return rotate_around_x(sc.x, sc.y); }
vec4 &rotate_around_y(const vec2 &sc) { return rotate_around_y(sc.x, sc.y); }
};
inline vec2::vec2(const vec4 &v) : x(v.x), y(v.y) {}
inline vec::vec(const vec4 &v) : x(v.x), y(v.y), z(v.z) {}
struct vec2
{
union
{
struct { float x, y; };
float v[2];
};
vec2() {}
vec2(float x, float y) : x(x), y(y) {}
explicit vec2(const vec &v) : x(v.x), y(v.y) {}
explicit vec2(const vec4 &v) : x(v.x), y(v.y) {}
float &operator[](int i) { return v[i]; }
float operator[](int i) const { return v[i]; }
bool operator==(const vec2 &o) const { return x == o.x && y == o.y; }
bool operator!=(const vec2 &o) const { return x != o.x || y != o.y; }
bool iszero() const { return x==0 && y==0; }
float dot(const vec2 &o) const { return x*o.x + y*o.y; }
float squaredlen() const { return dot(*this); }
float magnitude() const { return sqrtf(squaredlen()); }
vec2 &normalize() { mul(1/magnitude()); return *this; }
float cross(const vec2 &o) const { return x*o.y - y*o.x; }
vec2 &mul(float f) { x *= f; y *= f; return *this; }
vec2 &mul(const vec2 &o) { x *= o.x; y *= o.y; return *this; }
vec2 &div(float f) { x /= f; y /= f; return *this; }
vec2 &div(const vec2 &o) { x /= o.x; y /= o.y; return *this; }
vec2 &add(float f) { x += f; y += f; return *this; }
vec2 &add(const vec2 &o) { x += o.x; y += o.y; return *this; }
vec2 &sub(float f) { x -= f; y -= f; return *this; }
vec2 &sub(const vec2 &o) { x -= o.x; y -= o.y; return *this; }
vec2 &neg() { x = -x; y = -y; return *this; }
vec2 &lerp(const vec2 &b, float t) { x += (b.x-x)*t; y += (b.y-y)*t; return *this; }
vec2 &lerp(const vec2 &a, const vec2 &b, float t) { x = a.x + (b.x-a.x)*t; y = a.y + (b.y-a.y)*t; return *this; }
vec2 &avg(const vec2 &b) { add(b); mul(0.5f); return *this; }
};
inline vec::vec(const vec2 &v, float z) : x(v.x), y(v.y), z(z) {}
static inline bool htcmp(const vec2 &x, const vec2 &y)
{
return x == y;
}
static inline uint hthash(const vec2 &k)
{
union { uint i; float f; } x, y;
x.f = k.x; y.f = k.y;
uint v = x.i^y.i;
return v + (v>>12);
}
struct matrix3x3;
struct matrix3x4;
@ -650,11 +659,17 @@ struct matrix3x3
vec transform(const vec &o) const { return vec(a.dot(o), b.dot(o), c.dot(o)); }
vec transposedtransform(const vec &o) const
{
return vec(a.x*o.x + b.x*o.y + c.x*o.z,
a.y*o.x + b.y*o.y + c.y*o.z,
a.z*o.x + b.z*o.y + c.z*o.z);
return vec(a).mul(o.x).add(vec(b).mul(o.y)).add(vec(c).mul(o.z));
}
vec abstransform(const vec &o) const
{
return vec(a.absdot(o), b.absdot(o), c.absdot(o));
}
vec abstransposedtransform(const vec &o) const
{
return vec(a).mul(o.x).abs().add(vec(b).mul(o.y).abs()).add(vec(c).mul(o.z).abs());
}
void identity()
{
a = vec(1, 0, 0);
@ -670,6 +685,7 @@ struct matrix3x3
c.rotate_around_x(ck, sk);
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
void rotate_around_y(float ck, float sk)
{
@ -679,6 +695,7 @@ struct matrix3x3
c.rotate_around_y(ck, sk);
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
void rotate_around_z(float ck, float sk)
{
@ -688,8 +705,10 @@ struct matrix3x3
c.rotate_around_z(ck, sk);
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
vec transform(const vec2 &o) const { return vec(a.x*o.x + a.y*o.y, b.x*o.x + b.y*o.y, c.x*o.y + c.y*o.y); }
vec transform(const vec2 &o) const { return vec(a.dot2(o), b.dot2(o), c.dot2(o)); }
vec transposedtransform(const vec2 &o) { return vec(a).mul(o.x).add(vec(b).mul(o.y)); }
};
struct matrix3x4
@ -855,6 +874,7 @@ struct matrix3x4
c.rotate_around_x(ck, sk);
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
void rotate_around_y(float ck, float sk)
{
@ -864,6 +884,7 @@ struct matrix3x4
c.rotate_around_y(ck, sk);
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
void rotate_around_z(float ck, float sk)
{
@ -873,6 +894,7 @@ struct matrix3x4
c.rotate_around_z(ck, sk);
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
vec transform(const vec &o) const { return vec(a.dot(o), b.dot(o), c.dot(o)); }
vec transposedtransform(const vec &o) const
@ -1241,32 +1263,35 @@ struct glmatrix
: a(m.a.x, m.b.x, m.c.x, 0), b(m.a.y, m.b.y, m.c.y, 0), c(m.a.z, m.b.z, m.c.z, 0), d(m.a.w, m.b.w, m.c.w, 1)
{}
void rotate_around_x(float angle)
void rotate_around_x(float ck, float sk)
{
float ck = cosf(angle), sk = sinf(angle);
vec4 rb = vec4(b).mul(ck).add(vec4(c).mul(sk)),
rc = vec4(c).mul(ck).sub(vec4(b).mul(sk));
b = rb;
c = rc;
}
void rotate_around_x(float angle) { rotate_around_x(cosf(angle), sinf(angle)); }
void rotate_around_x(const vec2 &sc) { rotate_around_x(sc.x, sc.y); }
void rotate_around_y(float angle)
void rotate_around_y(float ck, float sk)
{
float ck = cosf(angle), sk = sinf(angle);
vec4 rc = vec4(c).mul(ck).add(vec4(a).mul(sk)),
ra = vec4(a).mul(ck).sub(vec4(c).mul(sk));
c = rc;
a = ra;
}
void rotate_around_y(float angle) { rotate_around_y(cosf(angle), sinf(angle)); }
void rotate_around_y(const vec2 &sc) { rotate_around_y(sc.x, sc.y); }
void rotate_around_z(float angle)
void rotate_around_z(float ck, float sk)
{
float ck = cosf(angle), sk = sinf(angle);
vec4 ra = vec4(a).mul(ck).add(vec4(b).mul(sk)),
rb = vec4(b).mul(ck).sub(vec4(a).mul(sk));
a = ra;
b = rb;
}
void rotate_around_z(float angle) { rotate_around_z(cosf(angle), sinf(angle)); }
void rotate_around_z(const vec2 &sc) { rotate_around_z(sc.x, sc.y); }
void rotate(float ck, float sk, const vec &dir)
{
@ -1281,11 +1306,8 @@ struct glmatrix
c = rc;
}
void rotate(float angle, const vec &dir)
{
float ck = cosf(angle), sk = sinf(angle);
rotate(ck, sk, dir);
}
void rotate(float angle, const vec &dir) { rotate(cosf(angle), sinf(angle), dir); }
void rotate(const vec2 &sc, const vec &dir) { rotate(sc.x, sc.y, dir); }
void mul(const glmatrix &x, const glmatrix &y)
{
@ -1535,3 +1557,12 @@ extern bool linecylinderintersect(const vec &from, const vec &to, const vec &sta
extern const vec2 sincos360[];
static inline int mod360(int angle)
{
if(angle < 0) angle = 360 + (angle <= -360 ? angle%360 : angle);
else if(angle >= 360) angle %= 360;
return angle;
}
static inline const vec2 &sincosmod360(int angle) { return sincos360[mod360(angle)]; }