1 /*
2  Copyright (c) 2013 yvt
3 
4  This file is part of OpenSpades.
5 
6  OpenSpades is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OpenSpades is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OpenSpades.  If not, see <http://www.gnu.org/licenses/>.
18 
19  */
20 
21 #include "Corpse.h"
22 #include <Core/Debug.h>
23 #include <Core/Settings.h>
24 #include "GameMap.h"
25 #include "IModel.h"
26 #include "IRenderer.h"
27 #include "Player.h"
28 #include "World.h"
29 
30 using namespace std;
31 
32 DEFINE_SPADES_SETTING(r_corpseLineCollision, "1");
33 
34 namespace spades {
35 	namespace client {
Corpse(IRenderer * renderer,GameMap * map,Player * p)36 		Corpse::Corpse(IRenderer *renderer, GameMap *map, Player *p)
37 		    : renderer(renderer), map(map) {
38 			SPADES_MARK_FUNCTION();
39 
40 			playerId = p->GetId();
41 
42 			IntVector3 col = p->GetWorld()->GetTeam(p->GetTeamId()).color;
43 			color = MakeVector3(col.x / 255.f, col.y / 255.f, col.z / 255.f);
44 
45 			bool crouch = p->GetInput().crouch;
46 			Vector3 front = p->GetFront();
47 
48 			float yaw = atan2(front.y, front.x) + static_cast<float>(M_PI) * .5f;
49 			// float pitch = -atan2(front.z, sqrt(front.x * front.x + front.y * front.y));
50 
51 			// lower axis
52 			Matrix4 lower = Matrix4::Translate(p->GetOrigin());
53 			lower = lower * Matrix4::Rotate(MakeVector3(0, 0, 1), yaw);
54 
55 			Matrix4 torso;
56 
57 			if (crouch) {
58 				lower = lower * Matrix4::Translate(0, 0, -0.4f);
59 				torso = lower * Matrix4::Translate(0, 0, -0.3f);
60 
61 				SetNode(Torso1, torso * MakeVector3(0.4f, -.15f, 0.1f));
62 				SetNode(Torso2, torso * MakeVector3(-0.4f, -.15f, 0.1f));
63 				SetNode(Torso3, torso * MakeVector3(-0.4f, .8f, 0.7f));
64 				SetNode(Torso4, torso * MakeVector3(0.4f, .8f, 0.7f));
65 
66 				SetNode(Leg1, lower * MakeVector3(-0.4f, .1f, 1.f));
67 				SetNode(Leg2, lower * MakeVector3(0.4f, .1f, 1.f));
68 
69 				SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
70 				SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
71 
72 			} else {
73 				torso = lower * Matrix4::Translate(0, 0, -1.1f);
74 
75 				SetNode(Torso1, torso * MakeVector3(0.4f, 0.f, 0.1f));
76 				SetNode(Torso2, torso * MakeVector3(-0.4f, 0.f, 0.1f));
77 				SetNode(Torso3, torso * MakeVector3(-0.4f, .0f, 1.f));
78 				SetNode(Torso4, torso * MakeVector3(0.4f, .0f, 1.f));
79 
80 				SetNode(Leg1, lower * MakeVector3(-0.4f, .0f, 1.f));
81 				SetNode(Leg2, lower * MakeVector3(0.4f, .0f, 1.f));
82 
83 				SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
84 				SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
85 			}
86 
87 			SetNode(Head,
88 			        (nodes[Torso1].pos + nodes[Torso2].pos) * .5f + MakeVector3(0, 0, -0.6f));
89 		}
90 
SetNode(NodeType n,spades::Vector3 v)91 		void Corpse::SetNode(NodeType n, spades::Vector3 v) {
92 			auto velNoise = [&] { return (SampleRandomFloat() - SampleRandomFloat()) * 2.0f; };
93 
94 			SPAssert(n >= 0);
95 			SPAssert(n < NodeCount);
96 
97 			nodes[n].pos = v;
98 			nodes[n].vel = MakeVector3(velNoise(), velNoise(), 0.f);
99 			nodes[n].lastPos = v;
100 			nodes[n].lastForce = MakeVector3(0, 0, 0);
101 		}
SetNode(NodeType n,spades::Vector4 v)102 		void Corpse::SetNode(NodeType n, spades::Vector4 v) {
103 			SetNode(n, v.GetXYZ());
104 		}
105 
~Corpse()106 		Corpse::~Corpse() {}
107 
Spring(NodeType n1,NodeType n2,float distance,float dt)108 		void Corpse::Spring(NodeType n1, NodeType n2, float distance, float dt) {
109 			SPADES_MARK_FUNCTION_DEBUG();
110 			SPAssert(n1 >= 0);
111 			SPAssert(n1 < NodeCount);
112 			SPAssert(n2 >= 0);
113 			SPAssert(n2 < NodeCount);
114 			Node &a = nodes[n1];
115 			Node &b = nodes[n2];
116 			Vector3 diff = b.pos - a.pos;
117 			float dist = diff.GetLength();
118 			Vector3 force = diff.Normalize() * (distance - dist);
119 			force *= dt * 50.f;
120 
121 			b.vel += force;
122 			a.vel -= force;
123 
124 			b.pos += force / (dt * 50.f) * 0.5f;
125 			a.pos -= force / (dt * 50.f) * 0.5f;
126 
127 			Vector3 velMid = (a.vel + b.vel) * .5f;
128 			float dump = 1.f - powf(.1f, dt);
129 			a.vel += (velMid - a.vel) * dump;
130 			b.vel += (velMid - b.vel) * dump;
131 		}
Spring(NodeType n1a,NodeType n1b,NodeType n2,float distance,float dt)132 		void Corpse::Spring(NodeType n1a, NodeType n1b, NodeType n2, float distance, float dt) {
133 			SPADES_MARK_FUNCTION_DEBUG();
134 			SPAssert(n1a >= 0);
135 			SPAssert(n1a < NodeCount);
136 			SPAssert(n1b >= 0);
137 			SPAssert(n1b < NodeCount);
138 			SPAssert(n2 >= 0);
139 			SPAssert(n2 < NodeCount);
140 			Node &x = nodes[n1a];
141 			Node &y = nodes[n1b];
142 			Node &b = nodes[n2];
143 			Vector3 diff = b.pos - (x.pos + y.pos) * .5f;
144 			float dist = diff.GetLength();
145 			Vector3 force = diff.Normalize() * (distance - dist);
146 			force *= dt * 50.f;
147 
148 			b.vel += force;
149 			force *= .5f;
150 			x.vel -= force;
151 			y.vel -= force;
152 
153 			Vector3 velMid = (x.vel + y.vel) * .25f + b.vel * .5f;
154 			float dump = 1.f - powf(.05f, dt);
155 			x.vel += (velMid - x.vel) * dump;
156 			y.vel += (velMid - y.vel) * dump;
157 			b.vel += (velMid - b.vel) * dump;
158 		}
159 
MyACos(float v)160 		static float MyACos(float v) {
161 			SPAssert(!std::isnan(v));
162 			if (v >= 1.f)
163 				return 0.f;
164 			if (v <= -1.f)
165 				return static_cast<float>(M_PI);
166 			float vv = acosf(v);
167 			if (std::isnan(vv)) {
168 				vv = acosf(v * .9999f);
169 			}
170 			SPAssert(!std::isnan(vv));
171 			return vv;
172 		}
173 
AngleSpring(NodeType base,NodeType n1id,NodeType n2id,float minDot,float maxDot,float dt)174 		void Corpse::AngleSpring(NodeType base, NodeType n1id, NodeType n2id, float minDot,
175 		                         float maxDot, float dt) {
176 			Node &nBase = nodes[base];
177 			Node &n1 = nodes[n1id];
178 			Node &n2 = nodes[n2id];
179 			Vector3 d1 = n1.pos - nBase.pos;
180 			Vector3 d2 = n2.pos - nBase.pos;
181 			float ln1 = d1.GetLength();
182 			float ln2 = d2.GetLength();
183 			float dot = Vector3::Dot(d1, d2) / (ln1 * ln2 + 0.0000001f);
184 
185 			if (dot >= minDot && dot <= maxDot)
186 				return;
187 
188 			Vector3 diff = n2.pos - n1.pos;
189 			float strength = 0.f;
190 
191 			Vector3 a1 = Vector3::Cross(d1, diff);
192 			a1 = Vector3::Cross(d1, a1).Normalize();
193 
194 			Vector3 a2 = Vector3::Cross(d2, diff);
195 			a2 = Vector3::Cross(d2, a2).Normalize();
196 
197 			// a1=-a1; a2=-a2;
198 			// a1 = -a1;
199 			a2 = -a2;
200 
201 			if (dot > maxDot) {
202 				strength = MyACos(dot) - MyACos(maxDot);
203 			} else if (dot < minDot) {
204 				strength = MyACos(dot) - MyACos(minDot);
205 			}
206 
207 			SPAssert(!std::isnan(strength));
208 
209 			strength *= 20.f;
210 			strength *= dt;
211 
212 			a1 *= strength;
213 			a2 *= strength;
214 
215 			a2 *= 0.f;
216 
217 			n2.vel += a1;
218 			n1.vel += a2;
219 			nBase.vel -= a1 + a2;
220 
221 			/*
222 			d1 += a1 * 0.01;
223 			d2 += a2 * 0.01;
224 			float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength());
225 
226 			if(dot > maxDot){
227 			    if(nd < dot)
228 			        printf("GOOD %f -> %f\n", dot, nd);
229 			    else
230 			        printf("BAD %f -> %f\n", dot, nd);
231 			}else{
232 			    if(nd > dot)
233 			        printf("GOOD %f -> %f\n", dot, nd);
234 			    else
235 			        printf("BAD %f -> %f\n", dot, nd);
236 			}*/
237 		}
AngleSpring(NodeType n1id,NodeType n2id,Vector3 dir,float minDot,float maxDot,float dt)238 		void Corpse::AngleSpring(NodeType n1id, NodeType n2id, Vector3 dir, float minDot,
239 		                         float maxDot, float dt) {
240 			Node &n1 = nodes[n1id];
241 			Node &n2 = nodes[n2id];
242 			Vector3 diff = n2.pos - n1.pos;
243 			float ln1 = diff.GetLength();
244 			float dot = Vector3::Dot(diff, dir) / (ln1 + 0.000000001f);
245 
246 			if (dot >= minDot && dot <= maxDot)
247 				return;
248 
249 			float strength = 0.f;
250 
251 			Vector3 a1 = Vector3::Cross(dir, diff);
252 			a1 = Vector3::Cross(diff, a1).Normalize();
253 
254 			Vector3 a2 = -a1;
255 			// a1=-a1; a2=-a2;
256 			// a1 = -a1;
257 
258 			if (dot > maxDot) {
259 				strength = MyACos(dot) - MyACos(maxDot);
260 			} else if (dot < minDot) {
261 				strength = MyACos(dot) - MyACos(minDot);
262 			}
263 
264 			SPAssert(!std::isnan(strength));
265 
266 			strength *= 100.f;
267 			strength *= dt;
268 
269 			a1 *= strength;
270 			a2 *= strength;
271 
272 			n2.vel += a1;
273 			n1.vel += a2;
274 			// nBase.vel -= a1 + a2;
275 
276 			/*
277 			 d1 += a1 * 0.01;
278 			 d2 += a2 * 0.01;
279 			 float nd = Vector3::Dot(d1, d2) / (d1.GetLength() * d2.GetLength());
280 
281 			 if(dot > maxDot){
282 			 if(nd < dot)
283 			 printf("GOOD %f -> %f\n", dot, nd);
284 			 else
285 			 printf("BAD %f -> %f\n", dot, nd);
286 			 }else{
287 			 if(nd > dot)
288 			 printf("GOOD %f -> %f\n", dot, nd);
289 			 else
290 			 printf("BAD %f -> %f\n", dot, nd);
291 			 }*/
292 		}
293 
fractf(float v)294 		static float fractf(float v) { return v - floorf(v); }
295 
CheckEscape(GameMap * map,IntVector3 hitBlock,IntVector3 a,IntVector3 b,IntVector3 dir,float & bestDist,IntVector3 & bestDir)296 		static void CheckEscape(GameMap *map, IntVector3 hitBlock, IntVector3 a, IntVector3 b,
297 		                        IntVector3 dir, float &bestDist, IntVector3 &bestDir) {
298 			hitBlock += dir;
299 			IntVector3 aa = a + dir;
300 			IntVector3 bb = b + dir;
301 			if (map->IsSolidWrapped(hitBlock.x, hitBlock.y, hitBlock.z))
302 				return;
303 			if (map->IsSolidWrapped(aa.x, aa.y, aa.z))
304 				return;
305 			if (map->IsSolidWrapped(bb.x, bb.y, bb.z))
306 				return;
307 			float dist;
308 			if (dir.x == 1) {
309 				dist = 1.f - fractf(a.x);
310 				dist += 1.f - fractf(b.x);
311 			} else if (dir.x == -1) {
312 				dist = fractf(a.x);
313 				dist += fractf(b.x);
314 			} else if (dir.y == 1) {
315 				dist = 1.f - fractf(a.y);
316 				dist += 1.f - fractf(b.y);
317 			} else if (dir.y == -1) {
318 				dist = fractf(a.y);
319 				dist += fractf(b.y);
320 			} else if (dir.z == 1) {
321 				dist = 1.f - fractf(a.z);
322 				dist += 1.f - fractf(b.z);
323 			} else if (dir.z == -1) {
324 				dist = fractf(a.z);
325 				dist += fractf(b.z);
326 			} else {
327 				SPAssert(false);
328 				return;
329 			}
330 
331 			if (dist < bestDist) {
332 				bestDist = dist;
333 				bestDir = dir;
334 			}
335 		}
336 
LineCollision(NodeType a,NodeType b,float dt)337 		void Corpse::LineCollision(NodeType a, NodeType b, float dt) {
338 			if (!r_corpseLineCollision)
339 				return;
340 			Node &n1 = nodes[a];
341 			Node &n2 = nodes[b];
342 
343 			IntVector3 hitBlock;
344 
345 			if (map->CastRay(n1.lastPos, n2.lastPos, 16.f, hitBlock)) {
346 				GameMap::RayCastResult res1 = map->CastRay2(n1.lastPos, n2.lastPos - n1.lastPos, 8);
347 				GameMap::RayCastResult res2 = map->CastRay2(n2.lastPos, n1.lastPos - n2.lastPos, 8);
348 
349 				if (!res1.hit)
350 					return;
351 				if (!res2.hit)
352 					return;
353 				if (res1.startSolid || res2.startSolid) {
354 					return;
355 				}
356 
357 				// really hit?
358 				if (Vector3::Dot(res1.hitPos - n1.lastPos, n2.lastPos - n1.lastPos) >
359 				    (n2.pos - n1.pos).GetPoweredLength()) {
360 					return;
361 				}
362 				if (Vector3::Dot(res1.hitPos - n1.lastPos, n2.lastPos - n1.lastPos) < 0.f) {
363 					return;
364 				}
365 				if (Vector3::Dot(res2.hitPos - n2.lastPos, n1.lastPos - n2.lastPos) >
366 				    (n2.pos - n1.pos).GetPoweredLength()) {
367 					return;
368 				}
369 				if (Vector3::Dot(res2.hitPos - n2.lastPos, n1.lastPos - n2.lastPos) < 0.f) {
370 					return;
371 				}
372 
373 				Vector3 blockPos;
374 				blockPos.x = hitBlock.x + .5f;
375 				blockPos.y = hitBlock.y + .5f;
376 				blockPos.z = hitBlock.z + .5f;
377 
378 				float inlen = (res1.hitPos - res2.hitPos).GetLength();
379 
380 				IntVector3 ivec = {0, 0, 0};
381 
382 				ivec.x += res1.normal.x;
383 				ivec.y += res1.normal.y;
384 				ivec.z += res1.normal.z;
385 				ivec.x += res2.normal.x;
386 				ivec.y += res2.normal.y;
387 				ivec.z += res2.normal.z;
388 
389 				Vector3 dir = {0.f, 0.f, 0.f};
390 				if (ivec.x == 0 && ivec.y == 0 && ivec.z == 0) {
391 					// hanging. which direction to escape?
392 					float bestDist = 1000.f;
393 					IntVector3 bestDir;
394 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
395 					            IntVector3::Make(1, 0, 0), bestDist, bestDir);
396 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
397 					            IntVector3::Make(-1, 0, 0), bestDist, bestDir);
398 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
399 					            IntVector3::Make(0, 1, 0), bestDist, bestDir);
400 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
401 					            IntVector3::Make(0, -1, 0), bestDist, bestDir);
402 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
403 					            IntVector3::Make(0, 0, 1), bestDist, bestDir);
404 					CheckEscape(map, hitBlock, n1.pos.Floor(), n2.pos.Floor(),
405 					            IntVector3::Make(0, 0, -1), bestDist, bestDir);
406 					if (bestDist > 10.f) {
407 						// failed to find appropriate direction.
408 						return;
409 					}
410 					ivec = bestDir;
411 					inlen = bestDist + .1f;
412 				}
413 				dir.x = ivec.x;
414 				dir.y = ivec.y;
415 				dir.z = ivec.z;
416 
417 				Vector3 normDir = dir; // |D|
418 
419 				n1.vel -= normDir * std::min(Vector3::Dot(normDir, n1.vel), 0.f);
420 				n2.vel -= normDir * std::min(Vector3::Dot(normDir, n2.vel), 0.f);
421 
422 				dir *= dt * inlen * 5.f;
423 
424 				n1.vel += dir;
425 				n2.vel += dir;
426 
427 				// friction
428 				n1.vel -= (n1.vel - normDir * Vector3::Dot(normDir, n1.vel)) * .2f;
429 				n2.vel -= (n2.vel - normDir * Vector3::Dot(normDir, n2.vel)) * .2f;
430 			}
431 		}
432 
AngularMomentum(int eId,NodeType a,NodeType b)433 		void Corpse::AngularMomentum(int eId, NodeType a, NodeType b) {
434 			Edge &e = edges[eId];
435 			e.velDiff = nodes[b].vel - nodes[a].vel;
436 			if (e.node1 != a || e.node2 != b) {
437 				e.lastVelDiff = e.velDiff;
438 				e.node1 = a;
439 				e.node2 = b;
440 				return;
441 			}
442 
443 			Vector3 force = e.lastVelDiff - e.velDiff;
444 			force *= .5f;
445 			nodes[b].vel += force;
446 			nodes[a].vel -= force;
447 
448 			e.lastVelDiff = e.velDiff;
449 		}
450 
ApplyConstraint(float dt)451 		void Corpse::ApplyConstraint(float dt) {
452 			SPADES_MARK_FUNCTION();
453 
454 			AngularMomentum(0, Torso1, Torso2);
455 			AngularMomentum(1, Torso2, Torso3);
456 			AngularMomentum(2, Torso3, Torso4);
457 			AngularMomentum(3, Torso4, Torso1);
458 			AngularMomentum(4, Torso1, Arm1);
459 			AngularMomentum(5, Torso2, Arm2);
460 			AngularMomentum(6, Torso3, Leg1);
461 			AngularMomentum(7, Torso4, Leg2);
462 
463 			Spring(Torso1, Torso2, 0.8f, dt);
464 			Spring(Torso3, Torso4, 0.8f, dt);
465 
466 			Spring(Torso1, Torso4, 0.9f, dt);
467 			Spring(Torso2, Torso3, 0.9f, dt);
468 
469 			Spring(Torso1, Torso3, 1.204f, dt);
470 			Spring(Torso2, Torso4, 1.204f, dt);
471 
472 			Spring(Arm1, Torso1, 1.f, dt);
473 			Spring(Arm2, Torso2, 1.f, dt);
474 			Spring(Leg1, Torso3, 1.f, dt);
475 			Spring(Leg2, Torso4, 1.f, dt);
476 
477 			AngleSpring(Torso1, Arm1, Torso3, -1.f, 0.6f, dt);
478 			AngleSpring(Torso2, Arm2, Torso4, -1.f, 0.6f, dt);
479 
480 			AngleSpring(Torso3, Leg1, Torso2, -1.f, -0.2f, dt);
481 			AngleSpring(Torso4, Leg2, Torso1, -1.f, -0.2f, dt);
482 
483 			Spring(Torso1, Torso2, Head, .6f, dt);
484 			/*
485 			AngleSpring(Torso1,
486 			            Torso2, Head,
487 			            0.5f, 1.f, dt);
488 
489 			AngleSpring(Torso2,
490 			            Torso1, Head,
491 			            0.5f, 1.f, dt);
492 			 */
493 
494 			LineCollision(Torso1, Torso2, dt);
495 			LineCollision(Torso2, Torso3, dt);
496 			LineCollision(Torso3, Torso4, dt);
497 			LineCollision(Torso4, Torso1, dt);
498 			LineCollision(Torso1, Torso3, dt);
499 			LineCollision(Torso2, Torso4, dt);
500 			LineCollision(Torso1, Arm1, dt);
501 			LineCollision(Torso2, Arm2, dt);
502 			LineCollision(Torso3, Leg1, dt);
503 			LineCollision(Torso4, Leg2, dt);
504 		}
505 
Update(float dt)506 		void Corpse::Update(float dt) {
507 			SPADES_MARK_FUNCTION();
508 			float damp = 1.f;
509 			float damp2 = 1.f;
510 			if (dt > 0.f) {
511 				damp = powf(.9f, dt);
512 				damp2 = powf(.371f, dt);
513 			}
514 			// dt *= 0.1f;
515 
516 			for (int i = 0; i < NodeCount; i++) {
517 				Node &node = nodes[i];
518 				Vector3 oldPos = node.lastPos;
519 				node.pos += node.vel * dt;
520 
521 				SPAssert(!std::isnan(node.pos.x));
522 				SPAssert(!std::isnan(node.pos.y));
523 				SPAssert(!std::isnan(node.pos.z));
524 
525 				if (node.pos.z > 63.f) {
526 					node.vel.z -= dt * 6.f; // buoyancy
527 					node.vel *= damp;
528 				} else {
529 					node.vel.z += dt * 32.f; // gravity
530 					node.vel.z *= damp2;
531 				}
532 
533 				// node.vel *= damp;
534 
535 				if (!map->ClipBox(oldPos.x, oldPos.y, oldPos.z)) {
536 
537 					if (map->ClipBox(node.pos.x, oldPos.y, oldPos.z)) {
538 						node.vel.x = -node.vel.x * .2f;
539 						if (fabsf(node.vel.x) < .3f)
540 							node.vel.x = 0.f;
541 						node.pos.x = oldPos.x;
542 
543 						node.vel.y *= .5f;
544 						node.vel.z *= .5f;
545 					}
546 
547 					if (map->ClipBox(node.pos.x, node.pos.y, oldPos.z)) {
548 						node.vel.y = -node.vel.y * .2f;
549 						if (fabsf(node.vel.y) < .3f)
550 							node.vel.y = 0.f;
551 						node.pos.y = oldPos.y;
552 
553 						node.vel.x *= .5f;
554 						node.vel.z *= .5f;
555 					}
556 
557 					if (map->ClipBox(node.pos.x, node.pos.y, node.pos.z)) {
558 						node.vel.z = -node.vel.z * .2f;
559 						if (fabsf(node.vel.z) < .3f)
560 							node.vel.z = 0.f;
561 						node.pos.z = oldPos.z;
562 
563 						node.vel.x *= .5f;
564 						node.vel.y *= .5f;
565 					}
566 
567 					if (map->ClipBox(node.pos.x, node.pos.y, node.pos.z)) {
568 						// TODO: getting out block
569 						// node.pos = oldPos;
570 						// node.vel *= .5f;
571 					}
572 				}
573 
574 				/*
575 				if(map->ClipBox(node.pos.x,
576 				                node.pos.y,
577 				                node.pos.z)){
578 				    if(!map->ClipBox(node.pos.x,
579 				                    node.pos.y,
580 				                    oldPos.z)){
581 				        node.vel.z = -node.vel.z * .2f;
582 				        if(fabsf(node.vel.z) < .3f)
583 				            node.vel.z = 0.f;
584 				        node.pos.z = oldPos.z;
585 				    }
586 				    if(!map->ClipBox(node.pos.x,
587 				                     oldPos.y,
588 				                     node.pos.z)){
589 				        node.vel.y = -node.vel.y * .2f;
590 				        if(fabsf(node.vel.y) < .3f)
591 				            node.vel.y = 0.f;
592 				        node.pos.y = oldPos.y;
593 				    }
594 				    if(!map->ClipBox(oldPos.x,
595 				                     node.pos.y,
596 				                     node.pos.z)){
597 				        node.vel.x = -node.vel.x * .2f;
598 				        if(fabsf(node.vel.x) < .3f)
599 				            node.vel.x = 0.f;
600 				        node.pos.x = oldPos.x;
601 				    }
602 				    node.vel *= .8f;
603 				    //node.pos = oldPos;
604 
605 				    if(node.vel.GetLength() < .02f){
606 				        node.vel *= 0.f;
607 				    }
608 				}*/
609 
610 				node.lastPos = node.pos;
611 				node.lastForce = node.vel;
612 			}
613 			ApplyConstraint(dt);
614 
615 			for (int i = 0; i < NodeCount; i++) {
616 				nodes[i].lastForce = nodes[i].vel - nodes[i].lastForce;
617 			}
618 		}
619 
AddToScene()620 		void Corpse::AddToScene() {
621 			ModelRenderParam param;
622 			param.customColor = color;
623 
624 			IModel *model;
625 			Matrix4 scaler = Matrix4::Scale(.1f);
626 
627 			// draw torso
628 			Matrix4 torso;
629 			Vector3 tX, tY;
630 			{
631 				Vector3 tX1 = nodes[Torso1].pos - nodes[Torso2].pos;
632 				Vector3 tX2 = nodes[Torso4].pos - nodes[Torso3].pos;
633 				Vector3 tY1 = nodes[Torso1].pos + nodes[Torso2].pos;
634 				Vector3 tY2 = nodes[Torso4].pos + nodes[Torso3].pos;
635 				tX = ((tX1 + tX2) * .5f).Normalize();
636 				tY = ((tY2 - tY1) * .5f).Normalize();
637 				Vector3 tZ = Vector3::Cross(tX, tY).Normalize();
638 				tY = Vector3::Cross(tX, tZ).Normalize();
639 				Vector3 tOrigin = tY1 * .5f;
640 				torso = Matrix4::FromAxis(tX, -tZ, -tY, tOrigin);
641 
642 				param.matrix = torso * scaler;
643 
644 				model = renderer->RegisterModel("Models/Player/Torso.kv6");
645 				renderer->RenderModel(model, param);
646 			}
647 			// draw Head
648 			{
649 				Vector3 headBase = (torso * MakeVector3(0.0f, 0.f, 0.f)).GetXYZ();
650 
651 				model = renderer->RegisterModel("Models/Player/Head.kv6");
652 
653 				Vector3 aX, aY, aZ;
654 				Vector3 center = (nodes[Torso1].pos + nodes[Torso2].pos) * .5f;
655 
656 				aZ = nodes[Head].pos - center;
657 				aZ = -torso.GetAxis(2);
658 				aZ = aZ.Normalize();
659 				aY = nodes[Torso2].pos - nodes[Torso1].pos;
660 				aY = Vector3::Cross(aY, aZ).Normalize();
661 				aX = Vector3::Cross(aY, aZ).Normalize();
662 				param.matrix = Matrix4::FromAxis(-aX, aY, -aZ, headBase) * scaler;
663 
664 				renderer->RenderModel(model, param);
665 			}
666 
667 			// draw Arms
668 			{
669 				Vector3 arm1Base = (torso * MakeVector3(0.4f, 0.f, 0.2f)).GetXYZ();
670 				Vector3 arm2Base = (torso * MakeVector3(-0.4f, 0.f, 0.2f)).GetXYZ();
671 
672 				model = renderer->RegisterModel("Models/Player/Arm.kv6");
673 
674 				Vector3 aX, aY, aZ;
675 
676 				aZ = nodes[Arm1].pos - nodes[Torso1].pos;
677 				aZ = aZ.Normalize();
678 				aY = nodes[Torso2].pos - nodes[Torso1].pos;
679 				aY = Vector3::Cross(aY, aZ).Normalize();
680 				aX = Vector3::Cross(aY, aZ).Normalize();
681 				param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm1Base) * scaler;
682 
683 				renderer->RenderModel(model, param);
684 
685 				aZ = nodes[Arm2].pos - nodes[Torso2].pos;
686 				aZ = aZ.Normalize();
687 				aY = nodes[Torso1].pos - nodes[Torso2].pos;
688 				aY = Vector3::Cross(aY, aZ).Normalize();
689 				aX = Vector3::Cross(aY, aZ).Normalize();
690 				param.matrix = Matrix4::FromAxis(aX, aY, aZ, arm2Base) * scaler;
691 
692 				renderer->RenderModel(model, param);
693 			}
694 
695 			// draw Leg
696 			{
697 				Vector3 leg1Base = (torso * MakeVector3(0.25f, 0.f, 0.9f)).GetXYZ();
698 				Vector3 leg2Base = (torso * MakeVector3(-0.25f, 0.f, 0.9f)).GetXYZ();
699 
700 				model = renderer->RegisterModel("Models/Player/Leg.kv6");
701 
702 				Vector3 aX, aY, aZ;
703 
704 				aZ = nodes[Leg1].pos - nodes[Torso3].pos;
705 				aZ = aZ.Normalize();
706 				aY = nodes[Torso1].pos - nodes[Torso2].pos;
707 				aY = Vector3::Cross(aY, aZ).Normalize();
708 				aX = Vector3::Cross(aY, aZ).Normalize();
709 				param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg1Base) * scaler;
710 
711 				renderer->RenderModel(model, param);
712 
713 				aZ = nodes[Leg2].pos - nodes[Torso4].pos;
714 				aZ = aZ.Normalize();
715 				aY = nodes[Torso1].pos - nodes[Torso2].pos;
716 				aY = Vector3::Cross(aY, aZ).Normalize();
717 				aX = Vector3::Cross(aY, aZ).Normalize();
718 				param.matrix = Matrix4::FromAxis(aX, aY, aZ, leg2Base) * scaler;
719 
720 				renderer->RenderModel(model, param);
721 			}
722 		}
723 
GetCenter()724 		Vector3 Corpse::GetCenter() {
725 			Vector3 v = {0, 0, 0};
726 			for (int i = 0; i < NodeCount; i++)
727 				v += nodes[i].pos;
728 			v *= 1.f / (float)NodeCount;
729 			return v;
730 		}
731 
IsVisibleFrom(spades::Vector3 eye)732 		bool Corpse::IsVisibleFrom(spades::Vector3 eye) {
733 			// distance culled?
734 			if ((eye - GetCenter()).GetLength() > 150.f)
735 				return false;
736 
737 			for (int i = 0; i < NodeCount; i++) {
738 				IntVector3 outBlk;
739 				if (map->CastRay(eye, nodes[i].pos, 256.f, outBlk))
740 					return true;
741 			}
742 			return false;
743 		}
744 
AddImpulse(spades::Vector3 v)745 		void Corpse::AddImpulse(spades::Vector3 v) {
746 			for (int i = 0; i < NodeCount; i++)
747 				nodes[i].vel += v;
748 		}
749 	}
750 }
751