summaryrefslogtreecommitdiffstats
path: root/src/Collision.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Collision.cpp')
-rw-r--r--src/Collision.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/Collision.cpp b/src/Collision.cpp
new file mode 100644
index 0000000..7c72922
--- /dev/null
+++ b/src/Collision.cpp
@@ -0,0 +1,97 @@
+/*
+ * Collision.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Collision.h"
+
+namespace Zoom {
+
+vmml::vec3f Collision::projectToEdge(const vmml::vec3f& p, const vmml::vec3f& v1, const vmml::vec3f& v2) {
+ vmml::vec3f pVec = p - v1;
+ vmml::vec3f edge = v2 - v1;
+
+ float lengthSq = edge.squared_length();
+ float edgeProj = vmml::dot(edge, pVec);
+
+ if(edgeProj < 0) return v1;
+ if(edgeProj > lengthSq) return v2;
+
+ return v1 + (edgeProj/lengthSq)*edge;
+}
+
+vmml::vec3f Collision::projectToNearestEdge(const vmml::vec3f& p, const Triangle &t) {
+ vmml::vec3f p1 = projectToEdge(p, t.getVertex(0), t.getVertex(1));
+ vmml::vec3f p2 = projectToEdge(p, t.getVertex(1), t.getVertex(2));
+ vmml::vec3f p3 = projectToEdge(p, t.getVertex(2), t.getVertex(0));
+
+ if(p.squared_distance(p1) < p.squared_distance(p2) && p.squared_distance(p1) < p.squared_distance(p3))
+ return p1;
+ else if(p.squared_distance(p2) < p.squared_distance(p3))
+ return p2;
+ else
+ return p3;
+}
+
+
+bool Collision::test(const Triangle &t, const MathUtil::Ray &ray, float *distance) {
+ vmml::vec3f edge1 = t.getVertex(1) - t.getVertex(0);
+ vmml::vec3f edge2 = t.getVertex(2) - t.getVertex(0);
+
+ vmml::vec3f pvec = ray.getDirection().cross(edge2);
+
+ float det = vmml::dot(edge1, pvec);
+ if(det < MathUtil::EPSILON)
+ return false;
+
+ vmml::vec3f tvec = ray.getVertex() - t.getVertex(0);
+ float u = vmml::dot(pvec, tvec);
+
+ if(u < 0 || u > det)
+ return false;
+
+ vmml::vec3f qvec = tvec.cross(edge1);
+ float v = vmml::dot(ray.getDirection(), qvec);
+ if(v < 0 || u+v > det)
+ return false;
+
+ if(distance)
+ *distance = vmml::dot(edge2, qvec) / det;
+
+ return true;
+}
+
+bool Collision::test(const Triangle &t, const vmml::vec3f &m, float r, const vmml::vec3f &move) {
+ float distance;
+
+ if(test(t, MathUtil::Ray(m - r*t.computeNormal(), move), &distance) && distance > -MathUtil::EPSILON) {
+ if(distance < 1)
+ return true;
+ else
+ return false;
+ }
+
+ vmml::vec3f collisionPoint = projectToNearestEdge(m, t);
+ vmml::vec3f movedPoint = projectToEdge(m, collisionPoint, collisionPoint - move);
+
+ if(m.squared_distance(movedPoint) < r*r)
+ return true;
+ else
+ return false;
+}
+
+}