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