2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "supertux/collision.hpp"
21 #include "math/aatriangle.hpp"
22 #include "math/rectf.hpp"
26 bool intersects(const Rectf& r1, const Rectf& r2)
28 if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
30 if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
36 //---------------------------------------------------------------------------
39 inline void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c)
41 n = Vector(p2.y-p1.y, p1.x-p2.x);
43 float nval = n.norm();
50 bool rectangle_aatriangle(Constraints* constraints, const Rectf& rect,
51 const AATriangle& triangle, const Vector& addl_ground_movement)
53 if(!intersects(rect, (const Rectf&) triangle))
60 switch(triangle.dir & AATriangle::DEFORM_MASK) {
62 area.p1 = triangle.bbox.p1;
63 area.p2 = triangle.bbox.p2;
65 case AATriangle::DEFORM_BOTTOM:
66 area.p1 = Vector(triangle.bbox.p1.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
67 area.p2 = triangle.bbox.p2;
69 case AATriangle::DEFORM_TOP:
70 area.p1 = triangle.bbox.p1;
71 area.p2 = Vector(triangle.bbox.p2.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
73 case AATriangle::DEFORM_LEFT:
74 area.p1 = triangle.bbox.p1;
75 area.p2 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p2.y);
77 case AATriangle::DEFORM_RIGHT:
78 area.p1 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p1.y);
79 area.p2 = triangle.bbox.p2;
85 switch(triangle.dir & AATriangle::DIRECTION_MASK) {
86 case AATriangle::SOUTHWEST:
87 p1 = Vector(rect.p1.x, rect.p2.y);
88 makePlane(area.p1, area.p2, normal, c);
90 case AATriangle::NORTHEAST:
91 p1 = Vector(rect.p2.x, rect.p1.y);
92 makePlane(area.p2, area.p1, normal, c);
94 case AATriangle::SOUTHEAST:
96 makePlane(Vector(area.p1.x, area.p2.y),
97 Vector(area.p2.x, area.p1.y), normal, c);
99 case AATriangle::NORTHWEST:
101 makePlane(Vector(area.p2.x, area.p1.y),
102 Vector(area.p1.x, area.p2.y), normal, c);
108 float n_p1 = -(normal * p1);
109 float depth = n_p1 - c;
114 std::cout << "R: " << rect << " Tri: " << triangle << "\n";
115 std::cout << "Norm: " << normal << " Depth: " << depth << "\n";
118 Vector outvec = normal * (depth + 0.2f);
120 const float RDELTA = 3;
121 if(p1.x < area.p1.x - RDELTA || p1.x > area.p2.x + RDELTA
122 || p1.y < area.p1.y - RDELTA || p1.y > area.p2.y + RDELTA) {
123 set_rectangle_rectangle_constraints(constraints, rect, area);
126 constraints->constrain_right(rect.get_right() + outvec.x, addl_ground_movement.x);
127 constraints->hit.right = true;
129 constraints->constrain_left(rect.get_left() + outvec.x, addl_ground_movement.x);
130 constraints->hit.left = true;
134 constraints->constrain_bottom(rect.get_bottom() + outvec.y, addl_ground_movement.y);
135 constraints->hit.bottom = true;
136 constraints->ground_movement += addl_ground_movement;
138 constraints->constrain_top(rect.get_top() + outvec.y, addl_ground_movement.y);
139 constraints->hit.top = true;
141 constraints->hit.slope_normal = normal;
147 void set_rectangle_rectangle_constraints(Constraints* constraints,
148 const Rectf& r1, const Rectf& r2, const Vector& addl_ground_movement)
150 float itop = r1.get_bottom() - r2.get_top();
151 float ibottom = r2.get_bottom() - r1.get_top();
152 float ileft = r1.get_right() - r2.get_left();
153 float iright = r2.get_right() - r1.get_left();
155 float vert_penetration = std::min(itop, ibottom);
156 float horiz_penetration = std::min(ileft, iright);
157 if(vert_penetration < horiz_penetration) {
159 constraints->constrain_bottom(r2.get_top(), addl_ground_movement.y);
160 constraints->hit.bottom = true;
161 constraints->ground_movement += addl_ground_movement;
163 constraints->constrain_top(r2.get_bottom(), addl_ground_movement.y);
164 constraints->hit.top = true;
168 constraints->constrain_right(r2.get_left(), addl_ground_movement.x);
169 constraints->hit.right = true;
171 constraints->constrain_left(r2.get_right(), addl_ground_movement.x);
172 constraints->hit.left = true;