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 : vec 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 :
218 3 : Model::Model(const vec &ent, const vec ¢er, const vec &radius, int yaw, int pitch, int roll) : o(ent), radius(radius)
219 : {
220 3 : orient.identity();
221 3 : if(roll)
222 : {
223 0 : orient.rotate_around_y(sincosmod360(roll));
224 : }
225 3 : if(pitch)
226 : {
227 0 : orient.rotate_around_x(sincosmod360(-pitch));
228 : }
229 3 : if(yaw)
230 : {
231 1 : orient.rotate_around_z(sincosmod360(-yaw));
232 : }
233 3 : o.add(orient.transposedtransform(center));
234 3 : }
235 :
236 1 : vec Model::center() const
237 : {
238 1 : return o;
239 : }
240 :
241 : //ModelOBB
242 :
243 0 : vec ModelOBB::contactface(const vec &wn, const vec &wdir) const
244 : {
245 0 : vec n = orient.transform(wn).div(radius),
246 0 : dir = orient.transform(wdir),
247 0 : an(std::fabs(n.x), std::fabs(n.y), dir.z ? std::fabs(n.z) : 0),
248 0 : fn(0, 0, 0);
249 0 : if(an.x > an.y)
250 : {
251 0 : if(an.x > an.z)
252 : {
253 0 : fn.x = n.x*dir.x < 0 ? (n.x > 0 ? 1 : -1) : 0;
254 : }
255 0 : else if(an.z > 0)
256 : {
257 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
258 : }
259 : }
260 0 : else if(an.y > an.z)
261 : {
262 0 : fn.y = n.y*dir.y < 0 ? (n.y > 0 ? 1 : -1) : 0;
263 : }
264 0 : else if(an.z > 0)
265 : {
266 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
267 : }
268 0 : return orient.transposedtransform(fn);
269 : }
270 :
271 0 : vec ModelOBB::supportpoint(const vec &n) const
272 : {
273 0 : vec ln = orient.transform(n),
274 0 : p(0, 0, 0);
275 0 : if(ln.x > 0)
276 : {
277 0 : p.x += radius.x;
278 : }
279 : else
280 : {
281 0 : p.x -= radius.x;
282 : }
283 0 : if(ln.y > 0)
284 : {
285 0 : p.y += radius.y;
286 : }
287 : else
288 : {
289 0 : p.y -= radius.y;
290 : }
291 0 : if(ln.z > 0)
292 : {
293 0 : p.z += radius.z;
294 : }
295 : else
296 : {
297 0 : p.z -= radius.z;
298 : }
299 0 : return orient.transposedtransform(p).add(o);
300 : }
301 :
302 : //ModelEllipse
303 :
304 0 : vec ModelEllipse::contactface(const vec &wn, const vec &wdir) const
305 : {
306 0 : vec n = orient.transform(wn).div(radius),
307 0 : dir = orient.transform(wdir);
308 0 : float dxy = n.dot2(n),
309 0 : dz = n.z*n.z;
310 0 : vec fn(0, 0, 0);
311 0 : if(dz > dxy && dir.z)
312 : {
313 0 : fn.z = n.z*dir.z < 0 ? (n.z > 0 ? 1 : -1) : 0;
314 : }
315 0 : else if(n.dot2(dir) < 0)
316 : {
317 0 : fn.x = n.x*radius.y;
318 0 : fn.y = n.y*radius.x;
319 0 : fn.normalize();
320 : }
321 0 : return orient.transposedtransform(fn);
322 : }
323 :
324 0 : vec ModelEllipse::supportpoint(const vec &n) const
325 : {
326 0 : vec ln = orient.transform(n),
327 0 : p(0, 0, 0);
328 0 : if(ln.z > 0)
329 : {
330 0 : p.z += radius.z;
331 : }
332 : else
333 : {
334 0 : p.z -= radius.z;
335 : }
336 0 : if(ln.x || ln.y)
337 : {
338 0 : float r = ln.magnitude2();
339 0 : p.x += ln.x*radius.x/r;
340 0 : p.y += ln.y*radius.y/r;
341 : }
342 0 : return orient.transposedtransform(p).add(o);
343 : }
344 : }
|