00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "supertux/collision.hpp"
00018
00019 #include <algorithm>
00020
00021 #include "math/aatriangle.hpp"
00022 #include "math/rectf.hpp"
00023
00024 namespace collision {
00025
00026 bool intersects(const Rectf& r1, const Rectf& r2)
00027 {
00028 if(r1.p2.x < r2.p1.x || r1.p1.x > r2.p2.x)
00029 return false;
00030 if(r1.p2.y < r2.p1.y || r1.p1.y > r2.p2.y)
00031 return false;
00032
00033 return true;
00034 }
00035
00036
00037
00038 namespace {
00039 inline void makePlane(const Vector& p1, const Vector& p2, Vector& n, float& c)
00040 {
00041 n = Vector(p2.y-p1.y, p1.x-p2.x);
00042 c = -(p2 * n);
00043 float nval = n.norm();
00044 n /= nval;
00045 c /= nval;
00046 }
00047
00048 }
00049
00050 bool rectangle_aatriangle(Constraints* constraints, const Rectf& rect,
00051 const AATriangle& triangle, const Vector& addl_ground_movement)
00052 {
00053 if(!intersects(rect, (const Rectf&) triangle))
00054 return false;
00055
00056 Vector normal;
00057 float c;
00058 Vector p1;
00059 Rectf area;
00060 switch(triangle.dir & AATriangle::DEFORM_MASK) {
00061 case 0:
00062 area.p1 = triangle.bbox.p1;
00063 area.p2 = triangle.bbox.p2;
00064 break;
00065 case AATriangle::DEFORM_BOTTOM:
00066 area.p1 = Vector(triangle.bbox.p1.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
00067 area.p2 = triangle.bbox.p2;
00068 break;
00069 case AATriangle::DEFORM_TOP:
00070 area.p1 = triangle.bbox.p1;
00071 area.p2 = Vector(triangle.bbox.p2.x, triangle.bbox.p1.y + triangle.bbox.get_height()/2);
00072 break;
00073 case AATriangle::DEFORM_LEFT:
00074 area.p1 = triangle.bbox.p1;
00075 area.p2 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p2.y);
00076 break;
00077 case AATriangle::DEFORM_RIGHT:
00078 area.p1 = Vector(triangle.bbox.p1.x + triangle.bbox.get_width()/2, triangle.bbox.p1.y);
00079 area.p2 = triangle.bbox.p2;
00080 break;
00081 default:
00082 assert(false);
00083 }
00084
00085 switch(triangle.dir & AATriangle::DIRECTION_MASK) {
00086 case AATriangle::SOUTHWEST:
00087 p1 = Vector(rect.p1.x, rect.p2.y);
00088 makePlane(area.p1, area.p2, normal, c);
00089 break;
00090 case AATriangle::NORTHEAST:
00091 p1 = Vector(rect.p2.x, rect.p1.y);
00092 makePlane(area.p2, area.p1, normal, c);
00093 break;
00094 case AATriangle::SOUTHEAST:
00095 p1 = rect.p2;
00096 makePlane(Vector(area.p1.x, area.p2.y),
00097 Vector(area.p2.x, area.p1.y), normal, c);
00098 break;
00099 case AATriangle::NORTHWEST:
00100 p1 = rect.p1;
00101 makePlane(Vector(area.p2.x, area.p1.y),
00102 Vector(area.p1.x, area.p2.y), normal, c);
00103 break;
00104 default:
00105 assert(false);
00106 }
00107
00108 float n_p1 = -(normal * p1);
00109 float depth = n_p1 - c;
00110 if(depth < 0)
00111 return false;
00112
00113 #if 0
00114 std::cout << "R: " << rect << " Tri: " << triangle << "\n";
00115 std::cout << "Norm: " << normal << " Depth: " << depth << "\n";
00116 #endif
00117
00118 Vector outvec = normal * (depth + 0.2f);
00119
00120 const float RDELTA = 3;
00121 if(p1.x < area.p1.x - RDELTA || p1.x > area.p2.x + RDELTA
00122 || p1.y < area.p1.y - RDELTA || p1.y > area.p2.y + RDELTA) {
00123 set_rectangle_rectangle_constraints(constraints, rect, area);
00124 } else {
00125 if(outvec.x < 0) {
00126 constraints->constrain_right(rect.get_right() + outvec.x, addl_ground_movement.x);
00127 constraints->hit.right = true;
00128 } else {
00129 constraints->constrain_left(rect.get_left() + outvec.x, addl_ground_movement.x);
00130 constraints->hit.left = true;
00131 }
00132
00133 if(outvec.y < 0) {
00134 constraints->constrain_bottom(rect.get_bottom() + outvec.y, addl_ground_movement.y);
00135 constraints->hit.bottom = true;
00136 constraints->ground_movement += addl_ground_movement;
00137 } else {
00138 constraints->constrain_top(rect.get_top() + outvec.y, addl_ground_movement.y);
00139 constraints->hit.top = true;
00140 }
00141 constraints->hit.slope_normal = normal;
00142 }
00143
00144 return true;
00145 }
00146
00147 void set_rectangle_rectangle_constraints(Constraints* constraints,
00148 const Rectf& r1, const Rectf& r2, const Vector& addl_ground_movement)
00149 {
00150 float itop = r1.get_bottom() - r2.get_top();
00151 float ibottom = r2.get_bottom() - r1.get_top();
00152 float ileft = r1.get_right() - r2.get_left();
00153 float iright = r2.get_right() - r1.get_left();
00154
00155 float vert_penetration = std::min(itop, ibottom);
00156 float horiz_penetration = std::min(ileft, iright);
00157 if(vert_penetration < horiz_penetration) {
00158 if(itop < ibottom) {
00159 constraints->constrain_bottom(r2.get_top(), addl_ground_movement.y);
00160 constraints->hit.bottom = true;
00161 constraints->ground_movement += addl_ground_movement;
00162 } else {
00163 constraints->constrain_top(r2.get_bottom(), addl_ground_movement.y);
00164 constraints->hit.top = true;
00165 }
00166 } else {
00167 if(ileft < iright) {
00168 constraints->constrain_right(r2.get_left(), addl_ground_movement.x);
00169 constraints->hit.right = true;
00170 } else {
00171 constraints->constrain_left(r2.get_right(), addl_ground_movement.x);
00172 constraints->hit.left = true;
00173 }
00174 }
00175 }
00176
00177 }
00178
00179