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 0 : vec CubePlanes::center() const
22 : {
23 0 : return p.o;
24 : }
25 :
26 0 : vec CubePlanes::supportpoint(const vec &n) const
27 : {
28 0 : int besti = 7;
29 0 : float bestd = n.dot(p.v[7]);
30 0 : for(int i = 0; i < 7; ++i)
31 : {
32 0 : float d = n.dot(p.v[i]);
33 0 : if(d > bestd)
34 : {
35 0 : besti = i;
36 0 : bestd = d;
37 : }
38 : }
39 0 : return p.v[besti];
40 : }
41 :
42 : //SolidCube
43 :
44 0 : vec SolidCube::center() const
45 : {
46 0 : return vec(o).add(size/2);
47 : }
48 :
49 0 : vec SolidCube::supportpoint (const vec &n) const
50 : {
51 0 : vec p(o);
52 0 : if(n.x > 0)
53 : {
54 0 : p.x += size;
55 : }
56 0 : if(n.y > 0)
57 : {
58 0 : p.y += size;
59 : }
60 0 : if(n.z > 0)
61 : {
62 0 : p.z += size;
63 : }
64 0 : return p;
65 : }
66 :
67 : //Ent
68 :
69 0 : vec Ent::center() const
70 : {
71 0 : return vec(ent->o.x, ent->o.y, ent->o.z + (ent->aboveeye - ent->eyeheight)/2);
72 : }
73 :
74 : //EntOBB
75 :
76 0 : EntOBB::EntOBB(const physent *ent) : Ent(ent)
77 : {
78 0 : orient.setyaw(ent->yaw/RAD);
79 0 : }
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 0 : vec EntOBB::localsupportpoint(const vec &ln) const
110 : {
111 0 : return vec(ln.x > 0 ? ent->xradius : -ent->xradius,
112 0 : ln.y > 0 ? ent->yradius : -ent->yradius,
113 0 : ln.z > 0 ? ent->aboveeye : -ent->eyeheight);
114 : }
115 0 : vec EntOBB::supportpoint(const vec &n) const
116 : {
117 0 : return orient.transposedtransform(localsupportpoint(orient.transform(n))).add(ent->o);
118 : }
119 :
120 0 : float EntOBB::supportcoordneg(const vec &p) const
121 : {
122 0 : return localsupportpoint(vec(p).neg()).dot(p);
123 : }
124 :
125 0 : float EntOBB::supportcoord(const vec &p) const
126 : {
127 0 : return localsupportpoint(p).dot(p);
128 : }
129 :
130 0 : float EntOBB::left() const { return supportcoordneg(orient.a) + ent->o.x; }
131 0 : float EntOBB::right() const { return supportcoord(orient.a) + ent->o.x; }
132 0 : float EntOBB::back() const { return supportcoordneg(orient.b) + ent->o.y; }
133 0 : float EntOBB::front() const { return supportcoord(orient.b) + ent->o.y; }
134 0 : float EntOBB::bottom() const { return ent->o.z - ent->eyeheight; }
135 0 : float EntOBB::top() const { return ent->o.z + ent->aboveeye; }
136 :
137 : //EntFuzzy
138 :
139 0 : float EntFuzzy::left() const { return ent->o.x - ent->radius; }
140 0 : float EntFuzzy::right() const { return ent->o.x + ent->radius; }
141 0 : float EntFuzzy::back() const { return ent->o.y - ent->radius; }
142 0 : float EntFuzzy::front() const { return ent->o.y + ent->radius; }
143 0 : float EntFuzzy::bottom() const { return ent->o.z - ent->eyeheight; }
144 0 : float EntFuzzy::top() const { return ent->o.z + ent->aboveeye; }
145 :
146 : //EntCylinder
147 :
148 0 : vec EntCylinder::contactface(const vec &n, const vec &dir) const
149 : {
150 0 : float dxy = n.dot2(n)/(ent->radius*ent->radius),
151 0 : dz = n.z*n.z*4/(ent->aboveeye + ent->eyeheight);
152 0 : vec fn(0, 0, 0);
153 0 : if(dz > dxy && dir.z)
154 : {
155 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
156 : }
157 0 : else if(n.dot2(dir) < 0)
158 : {
159 0 : fn.x = n.x;
160 0 : fn.y = n.y;
161 0 : fn.normalize();
162 : }
163 0 : return fn;
164 : }
165 :
166 0 : vec EntCylinder::supportpoint(const vec &n) const
167 : {
168 0 : vec p(ent->o);
169 0 : if(n.z > 0)
170 : {
171 0 : p.z += ent->aboveeye;
172 : }
173 : else
174 : {
175 0 : p.z -= ent->eyeheight;
176 : }
177 0 : if(n.x || n.y)
178 : {
179 0 : float r = ent->radius / n.magnitude2();
180 0 : p.x += n.x*r;
181 0 : p.y += n.y*r;
182 : }
183 0 : return p;
184 : }
185 :
186 : //EntCapsule
187 :
188 0 : vec EntCapsule::supportpoint(const vec &n) const
189 : {
190 0 : vec p(ent->o);
191 0 : if(n.z > 0)
192 : {
193 0 : p.z += ent->aboveeye - ent->radius;
194 : }
195 : else
196 : {
197 0 : p.z -= ent->eyeheight - ent->radius;
198 : }
199 0 : p.add(vec(n).mul(ent->radius / n.magnitude()));
200 0 : return p;
201 : }
202 :
203 : //EntEllipsoid
204 :
205 0 : vec EntEllipsoid::supportpoint(const vec &dir) const
206 : {
207 0 : vec p(ent->o);
208 0 : vec n = vec(dir).normalize();
209 0 : p.x += ent->radius*n.x;
210 0 : p.y += ent->radius*n.y;
211 0 : p.z += (ent->aboveeye + ent->eyeheight)/2*(1 + n.z) - ent->eyeheight;
212 0 : return p;
213 : }
214 :
215 : //Model
216 :
217 0 : Model::Model(const vec &ent, const vec ¢er, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
218 : {
219 0 : orient.identity();
220 0 : if(roll)
221 : {
222 0 : orient.rotate_around_y(sincosmod360(roll));
223 : }
224 0 : if(pitch)
225 : {
226 0 : orient.rotate_around_x(sincosmod360(-pitch));
227 : }
228 0 : if(yaw)
229 : {
230 0 : orient.rotate_around_z(sincosmod360(-yaw));
231 : }
232 0 : o.add(orient.transposedtransform(center));
233 0 : }
234 :
235 0 : vec Model::center() const
236 : {
237 0 : return o;
238 : }
239 :
240 : //ModelOBB
241 :
242 0 : vec ModelOBB::contactface(const vec &wn, const vec &wdir) const
243 : {
244 0 : vec n = orient.transform(wn).div(radius),
245 0 : dir = orient.transform(wdir),
246 0 : an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
247 0 : fn(0, 0, 0);
248 0 : if(an.x > an.y)
249 : {
250 0 : if(an.x > an.z)
251 : {
252 0 : fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
253 : }
254 0 : else if(an.z > 0)
255 : {
256 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
257 : }
258 : }
259 0 : else if(an.y > an.z)
260 : {
261 0 : fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
262 : }
263 0 : else if(an.z > 0)
264 : {
265 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
266 : }
267 0 : return orient.transposedtransform(fn);
268 : }
269 :
270 0 : vec ModelOBB::supportpoint(const vec &n) const
271 : {
272 0 : vec ln = orient.transform(n),
273 0 : p(0, 0, 0);
274 0 : if(ln.x > 0)
275 : {
276 0 : p.x += radius.x;
277 : }
278 : else
279 : {
280 0 : p.x -= radius.x;
281 : }
282 0 : if(ln.y > 0)
283 : {
284 0 : p.y += radius.y;
285 : }
286 : else
287 : {
288 0 : p.y -= radius.y;
289 : }
290 0 : if(ln.z > 0)
291 : {
292 0 : p.z += radius.z;
293 : }
294 : else
295 : {
296 0 : p.z -= radius.z;
297 : }
298 0 : return orient.transposedtransform(p).add(o);
299 : }
300 :
301 : //ModelEllipse
302 :
303 0 : vec ModelEllipse::contactface(const vec &wn, const vec &wdir) const
304 : {
305 0 : vec n = orient.transform(wn).div(radius),
306 0 : dir = orient.transform(wdir);
307 0 : float dxy = n.dot2(n),
308 0 : dz = n.z*n.z;
309 0 : vec fn(0, 0, 0);
310 0 : if(dz > dxy && dir.z)
311 : {
312 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
313 : }
314 0 : else if(n.dot2(dir) < 0)
315 : {
316 0 : fn.x = n.x*radius.y;
317 0 : fn.y = n.y*radius.x;
318 0 : fn.normalize();
319 : }
320 0 : return orient.transposedtransform(fn);
321 : }
322 :
323 0 : vec ModelEllipse::supportpoint(const vec &n) const
324 : {
325 0 : vec ln = orient.transform(n),
326 0 : p(0, 0, 0);
327 0 : if(ln.z > 0)
328 : {
329 0 : p.z += radius.z;
330 : }
331 : else
332 : {
333 0 : p.z -= radius.z;
334 : }
335 0 : if(ln.x || ln.y)
336 : {
337 0 : float r = ln.magnitude2();
338 0 : p.x += ln.x*radius.x/r;
339 0 : p.y += ln.y*radius.y/r;
340 : }
341 0 : return orient.transposedtransform(p).add(o);
342 : }
343 : }
|