Line data Source code
1 : /*This code is based off the Minkowski Portal Refinement algorithm by Gary Snethen
2 : * in XenoCollide & Game Programming Gems 7.
3 : *
4 : * Minkowski Portal Refinement is a way of finding whether two hulls intersect
5 : * efficiently, useful for finding if two models are intersecting quickly
6 : *
7 : * used in physics.cpp and for model-related collision purposes
8 : */
9 : #include "../libprimis-headers/cube.h"
10 : #include "../../shared/geomexts.h"
11 :
12 : #include "octaworld.h"
13 :
14 : #include "mpr.h"
15 :
16 : namespace mpr
17 : {
18 :
19 : //CubePlanes
20 :
21 1 : vec CubePlanes::center() const
22 : {
23 1 : return p.o;
24 : }
25 :
26 3 : vec CubePlanes::supportpoint(const vec &n) const
27 : {
28 3 : int besti = 7;
29 3 : float bestd = n.dot(p.v[7]);
30 24 : for(int i = 0; i < 7; ++i)
31 : {
32 21 : float d = n.dot(p.v[i]);
33 21 : if(d > bestd)
34 : {
35 3 : besti = i;
36 3 : bestd = d;
37 : }
38 : }
39 3 : return p.v[besti];
40 : }
41 :
42 : //SolidCube
43 :
44 2 : vec SolidCube::center() const
45 : {
46 2 : return vec(o).add(size/2);
47 : }
48 :
49 3 : vec SolidCube::supportpoint (const vec &n) const
50 : {
51 3 : vec p(o);
52 3 : if(n.x > 0)
53 : {
54 2 : p.x += size;
55 : }
56 3 : if(n.y > 0)
57 : {
58 3 : p.y += size;
59 : }
60 3 : if(n.z > 0)
61 : {
62 3 : p.z += size;
63 : }
64 3 : return p;
65 : }
66 :
67 : //Ent
68 :
69 3 : vec Ent::center() const
70 : {
71 3 : return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight)/2);
72 : }
73 :
74 : //EntOBB
75 :
76 7 : EntOBB::EntOBB(const physent *ent) : Ent(ent)
77 : {
78 7 : orient.setyaw(ent->yaw/RAD);
79 7 : }
80 :
81 0 : vec EntOBB::contactface(const vec &wn, const vec &wdir) const
82 : {
83 0 : vec n = orient.transform(wn).div(vec(ent->xradius, ent->yradius, (ent->aboveeye + ent->eyeheight)/2)),
84 0 : dir = orient.transform(wdir),
85 0 : an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
86 0 : fn(0, 0, 0);
87 0 : if(an.x > an.y)
88 : {
89 0 : if(an.x > an.z)
90 : {
91 0 : fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
92 : }
93 0 : else if(an.z > 0)
94 : {
95 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
96 : }
97 : }
98 0 : else if(an.y > an.z)
99 : {
100 0 : fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
101 : }
102 0 : else if(an.z > 0)
103 : {
104 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
105 : }
106 0 : return orient.transposedtransform(fn);
107 : }
108 :
109 9 : vec EntOBB::localsupportpoint(const vec &ln) const
110 : {
111 9 : return vec(ln.x > 0 ? ent->xradius : -ent->xradius,
112 9 : ln.y > 0 ? ent->yradius : -ent->yradius,
113 18 : ln.z > 0 ? ent->aboveeye : -ent->eyeheight);
114 : }
115 :
116 1 : vec EntOBB::supportpoint(const vec &n) const
117 : {
118 1 : return orient.transposedtransform(localsupportpoint(orient.transform(n))).add(ent->o);
119 : }
120 :
121 4 : float EntOBB::supportcoordneg(const vec &p) const
122 : {
123 4 : return localsupportpoint(vec(p).neg()).dot(p);
124 : }
125 :
126 4 : float EntOBB::supportcoord(const vec &p) const
127 : {
128 4 : return localsupportpoint(p).dot(p);
129 : }
130 :
131 2 : float EntOBB::left() const { return supportcoordneg(orient.a) + ent->o.x; }
132 2 : float EntOBB::right() const { return supportcoord(orient.a) + ent->o.x; }
133 2 : float EntOBB::back() const { return supportcoordneg(orient.b) + ent->o.y; }
134 2 : float EntOBB::front() const { return supportcoord(orient.b) + ent->o.y; }
135 1 : float EntOBB::bottom() const { return ent->o.z - ent->eyeheight; }
136 1 : float EntOBB::top() const { return ent->o.z + ent->aboveeye; }
137 :
138 : //EntFuzzy
139 :
140 1 : float EntFuzzy::left() const { return ent->o.x - ent->radius; }
141 1 : float EntFuzzy::right() const { return ent->o.x + ent->radius; }
142 1 : float EntFuzzy::back() const { return ent->o.y - ent->radius; }
143 1 : float EntFuzzy::front() const { return ent->o.y + ent->radius; }
144 2 : float EntFuzzy::bottom() const { return ent->o.z - ent->eyeheight; }
145 2 : float EntFuzzy::top() const { return ent->o.z + ent->aboveeye; }
146 :
147 : //EntCylinder
148 :
149 0 : vec EntCylinder::contactface(const vec &n, const vec &dir) const
150 : {
151 0 : float dxy = n.dot2(n)/(ent->radius*ent->radius),
152 0 : dz = n.z*n.z*4/(ent->aboveeye + ent->eyeheight);
153 0 : vec fn(0, 0, 0);
154 0 : if(dz > dxy && dir.z)
155 : {
156 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
157 : }
158 0 : else if(n.dot2(dir) < 0)
159 : {
160 0 : fn.x = n.x;
161 0 : fn.y = n.y;
162 0 : fn.normalize();
163 : }
164 0 : return fn;
165 : }
166 :
167 0 : vec EntCylinder::supportpoint(const vec &n) const
168 : {
169 0 : vec p(ent->o);
170 0 : if(n.z > 0)
171 : {
172 0 : p.z += ent->aboveeye;
173 : }
174 : else
175 : {
176 0 : p.z -= ent->eyeheight;
177 : }
178 0 : if(n.x || n.y)
179 : {
180 0 : float r = ent->radius / n.magnitude2();
181 0 : p.x += n.x*r;
182 0 : p.y += n.y*r;
183 : }
184 0 : return p;
185 : }
186 :
187 : //EntCapsule
188 :
189 0 : vec EntCapsule::supportpoint(const vec &n) const
190 : {
191 0 : vec p(ent->o);
192 0 : if(n.z > 0)
193 : {
194 0 : p.z += ent->aboveeye - ent->radius;
195 : }
196 : else
197 : {
198 0 : p.z -= ent->eyeheight - ent->radius;
199 : }
200 0 : p.add(vec(n).mul(ent->radius / n.magnitude()));
201 0 : return p;
202 : }
203 :
204 : //EntEllipsoid
205 :
206 0 : vec EntEllipsoid::supportpoint(const vec &dir) const
207 : {
208 0 : vec p(ent->o),
209 0 : n = vec(dir).normalize();
210 0 : p.x += ent->radius*n.x;
211 0 : p.y += ent->radius*n.y;
212 0 : p.z += (ent->aboveeye + ent->eyeheight)/2*(1 + n.z) - ent->eyeheight;
213 0 : return p;
214 : }
215 :
216 : //Model
217 3 : Model::~Model() {}
218 :
219 3 : Model::Model(const vec &ent, const vec ¢er, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
220 : {
221 3 : orient.identity();
222 3 : if(roll)
223 : {
224 0 : orient.rotate_around_y(sincosmod360(roll));
225 : }
226 3 : if(pitch)
227 : {
228 0 : orient.rotate_around_x(sincosmod360(-pitch));
229 : }
230 3 : if(yaw)
231 : {
232 1 : orient.rotate_around_z(sincosmod360(-yaw));
233 : }
234 3 : o.add(orient.transposedtransform(center));
235 3 : }
236 :
237 1 : vec Model::center() const
238 : {
239 1 : return o;
240 : }
241 :
242 : //ModelOBB
243 :
244 0 : vec ModelOBB::contactface(const vec &wn, const vec &wdir) const
245 : {
246 0 : vec n = orient.transform(wn).div(radius),
247 0 : dir = orient.transform(wdir),
248 0 : an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
249 0 : fn(0, 0, 0);
250 0 : if(an.x > an.y)
251 : {
252 0 : if(an.x > an.z)
253 : {
254 0 : fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
255 : }
256 0 : else if(an.z > 0)
257 : {
258 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
259 : }
260 : }
261 0 : else if(an.y > an.z)
262 : {
263 0 : fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
264 : }
265 0 : else if(an.z > 0)
266 : {
267 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
268 : }
269 0 : return orient.transposedtransform(fn);
270 : }
271 :
272 0 : vec ModelOBB::supportpoint(const vec &n) const
273 : {
274 0 : vec ln = orient.transform(n),
275 0 : p(0, 0, 0);
276 0 : if(ln.x > 0)
277 : {
278 0 : p.x += radius.x;
279 : }
280 : else
281 : {
282 0 : p.x -= radius.x;
283 : }
284 0 : if(ln.y > 0)
285 : {
286 0 : p.y += radius.y;
287 : }
288 : else
289 : {
290 0 : p.y -= radius.y;
291 : }
292 0 : if(ln.z > 0)
293 : {
294 0 : p.z += radius.z;
295 : }
296 : else
297 : {
298 0 : p.z -= radius.z;
299 : }
300 0 : return orient.transposedtransform(p).add(o);
301 : }
302 :
303 : //ModelEllipse
304 :
305 0 : vec ModelEllipse::contactface(const vec &wn, const vec &wdir) const
306 : {
307 0 : vec n = orient.transform(wn).div(radius),
308 0 : dir = orient.transform(wdir);
309 0 : float dxy = n.dot2(n),
310 0 : dz = n.z*n.z;
311 0 : vec fn(0, 0, 0);
312 0 : if(dz > dxy && dir.z)
313 : {
314 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
315 : }
316 0 : else if(n.dot2(dir) < 0)
317 : {
318 0 : fn.x = n.x*radius.y;
319 0 : fn.y = n.y*radius.x;
320 0 : fn.normalize();
321 : }
322 0 : return orient.transposedtransform(fn);
323 : }
324 :
325 0 : vec ModelEllipse::supportpoint(const vec &n) const
326 : {
327 0 : vec ln = orient.transform(n),
328 0 : p(0, 0, 0);
329 0 : if(ln.z > 0)
330 : {
331 0 : p.z += radius.z;
332 : }
333 : else
334 : {
335 0 : p.z -= radius.z;
336 : }
337 0 : if(ln.x || ln.y)
338 : {
339 0 : float r = ln.magnitude2();
340 0 : p.x += ln.x*radius.x/r;
341 0 : p.y += ln.y*radius.y/r;
342 : }
343 0 : return orient.transposedtransform(p).add(o);
344 : }
345 : }
|