b0cb2295de76757030add74f855f7702ba9fcecf
[supertux.git] / lib / special / collision.cpp
1 #include <config.h>
2
3 #include "collision.h"
4
5 #include <algorithm>
6 #include <iostream>
7 #include <stdio.h>
8 #include <float.h>
9 #include <math.h>
10 #include "math/vector.h"
11 #include "math/aatriangle.h"
12 #include "math/rectangle.h"
13 #include "collision_hit.h"
14
15 namespace SuperTux
16 {
17
18 static const float DELTA = .0001;
19
20 bool
21 Collision::rectangle_rectangle(CollisionHit& hit, const Rectangle& r1,
22     const Vector& movement, const Rectangle& r2)
23 {
24   if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
25     return false;
26   if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
27     return false;
28
29   float xr;
30   if(movement.x > DELTA) {
31     hit.depth = r1.p2.x - r2.p1.x;
32     hit.normal.x = -1;
33     hit.normal.y = 0;
34     xr = hit.depth / movement.x;
35   } else if(movement.x < -DELTA) {
36     hit.depth = r2.p2.x - r1.p1.x;
37     hit.normal.x = 1;
38     hit.normal.y = 0;
39     xr = hit.depth / -movement.x;
40   } else {
41     xr = FLT_MAX;
42     if(movement.y > -DELTA && movement.y < DELTA) {
43       return false;
44     }
45   }
46
47   if(movement.y > DELTA) {
48     float ydepth = r1.p2.y - r2.p1.y;
49     float yr = ydepth / movement.y;
50     if(yr < xr) {
51       hit.depth = ydepth;
52       hit.normal.x = 0;
53       hit.normal.y = -1;
54     }
55   } else if(movement.y < -DELTA) {
56     float ydepth = r2.p2.y - r1.p1.y;
57     float yr = ydepth / -movement.y;
58     if(yr < xr) {
59       hit.depth = ydepth;
60       hit.normal.x = 0;
61       hit.normal.y = 1;
62     }
63   }
64
65   return true;
66 }
67
68 //---------------------------------------------------------------------------
69
70 static void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c)
71 {
72   n = Vector(p2.y-p1.y, p1.x-p2.x);
73   c = -(p2 * n);
74   float nval = n.norm();             
75   n /= nval;
76   c /= nval;
77 }
78
79 bool
80 Collision::rectangle_aatriangle(CollisionHit& hit, const Rectangle& rect,
81     const Vector& movement, const AATriangle& triangle)
82 {
83   if(!rectangle_rectangle(hit, rect, movement, (const Rectangle&) triangle))
84     return false;
85   
86   Vector normal;
87   float c;
88   Vector p1;
89   switch(triangle.dir) {
90     case AATriangle::SOUTHWEST:
91       p1 = Vector(rect.p1.x, rect.p2.y);
92       makePlane(triangle.p1, triangle.p2, normal, c);
93       break;
94     case AATriangle::NORTHEAST:
95       p1 = Vector(rect.p2.x, rect.p1.y);
96       makePlane(triangle.p2, triangle.p1, normal, c);
97       break;
98     case AATriangle::SOUTHEAST:
99       p1 = rect.p2;
100       makePlane(Vector(triangle.p1.x, triangle.p2.y),
101           Vector(triangle.p2.x, triangle.p1.y), normal, c);
102       break;
103     case AATriangle::NORTHWEST:
104       p1 = rect.p1;
105       makePlane(Vector(triangle.p2.x, triangle.p1.y),
106           Vector(triangle.p1.x, triangle.p2.y), normal, c);
107       break;
108   }
109
110   float depth = -(normal * p1) - c;
111   if(depth < 0)
112     return false;
113   if(depth < hit.depth) {
114     hit.depth = depth;
115     hit.normal = normal;
116   }
117
118   return true;
119 }
120
121 }