|
20 | 20 | #include "MapTree.h" |
21 | 21 | #include "ModelInstance.h" |
22 | 22 | #include "ModelIgnoreFlags.h" |
| 23 | +#include <array> |
23 | 24 |
|
24 | 25 | using G3D::Vector3; |
25 | | -using G3D::Ray; |
26 | 26 |
|
27 | 27 | template<> struct BoundsTrait<VMAP::GroupModel> |
28 | 28 | { |
@@ -416,17 +416,46 @@ namespace VMAP |
416 | 416 | return callback.hit; |
417 | 417 | } |
418 | 418 |
|
419 | | - bool GroupModel::IsInsideObject(Vector3 const& pos, Vector3 const& down, float& z_dist) const |
| 419 | + inline bool IsInsideOrAboveBound(G3D::AABox const& bounds, const G3D::Point3& point) |
420 | 420 | { |
421 | | - if (triangles.empty() || !iBound.contains(pos)) |
422 | | - return false; |
423 | | - Vector3 rPos = pos - 0.1f * down; |
424 | | - float dist = G3D::finf(); |
425 | | - G3D::Ray ray(rPos, down); |
426 | | - bool hit = IntersectRay(ray, dist, false); |
427 | | - if (hit) |
428 | | - z_dist = dist - 0.1f; |
429 | | - return hit; |
| 421 | + return point.x >= bounds.low().x |
| 422 | + && point.y >= bounds.low().y |
| 423 | + && point.z >= bounds.low().z |
| 424 | + && point.x <= bounds.high().x |
| 425 | + && point.y <= bounds.high().y; |
| 426 | + } |
| 427 | + |
| 428 | + GroupModel::InsideResult GroupModel::IsInsideObject(G3D::Ray const& ray, float& z_dist) const |
| 429 | + { |
| 430 | + if (triangles.empty() || !IsInsideOrAboveBound(iBound, ray.origin())) |
| 431 | + return OUT_OF_BOUNDS; |
| 432 | + |
| 433 | + if (meshTree.bound().high().z >= ray.origin().z) |
| 434 | + { |
| 435 | + float dist = G3D::finf(); |
| 436 | + if (IntersectRay(ray, dist, false)) |
| 437 | + { |
| 438 | + z_dist = dist - 0.1f; |
| 439 | + return INSIDE; |
| 440 | + } |
| 441 | + if (meshTree.bound().contains(ray.origin())) |
| 442 | + return MAYBE_INSIDE; |
| 443 | + } |
| 444 | + else |
| 445 | + { |
| 446 | + // some group models don't have any floor to intersect with |
| 447 | + // so we should attempt to intersect with a model part below this group |
| 448 | + // then find back where we originated from (in WorldModel::GetLocationInfo) |
| 449 | + float dist = G3D::finf(); |
| 450 | + float delta = ray.origin().z - meshTree.bound().high().z; |
| 451 | + if (IntersectRay(ray.bumpedRay(delta), dist, false)) |
| 452 | + { |
| 453 | + z_dist = dist - 0.1f + delta; |
| 454 | + return ABOVE; |
| 455 | + } |
| 456 | + } |
| 457 | + |
| 458 | + return OUT_OF_BOUNDS; |
430 | 459 | } |
431 | 460 |
|
432 | 461 | bool GroupModel::GetLiquidLevel(Vector3 const& pos, float& liqHeight) const |
@@ -492,55 +521,60 @@ namespace VMAP |
492 | 521 | return isc.hit; |
493 | 522 | } |
494 | 523 |
|
495 | | - class WModelAreaCallback { |
496 | | - public: |
497 | | - WModelAreaCallback(std::vector<GroupModel> const& vals, Vector3 const& down) : |
498 | | - prims(vals.begin()), hit(vals.end()), minVol(G3D::finf()), zDist(G3D::finf()), zVec(down) { } |
499 | | - std::vector<GroupModel>::const_iterator prims; |
500 | | - std::vector<GroupModel>::const_iterator hit; |
501 | | - float minVol; |
502 | | - float zDist; |
503 | | - Vector3 zVec; |
504 | | - void operator()(Vector3 const& point, uint32 entry) |
| 524 | + class WModelAreaCallback |
| 525 | + { |
| 526 | + public: |
| 527 | + WModelAreaCallback(std::vector<GroupModel> const& vals) : |
| 528 | + prims(vals), hit() { } |
| 529 | + std::vector<GroupModel> const& prims; |
| 530 | + std::array<GroupModel const*, 3> hit; |
| 531 | + |
| 532 | + bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*stopAtFirstHit*/) |
| 533 | + { |
| 534 | + float group_Z; |
| 535 | + if (GroupModel::InsideResult result = prims[entry].IsInsideObject(ray, group_Z); result != GroupModel::OUT_OF_BOUNDS) |
505 | 536 | { |
506 | | - float group_Z; |
507 | | - //float pVol = prims[entry].GetBound().volume(); |
508 | | - //if (pVol < minVol) |
509 | | - //{ |
510 | | - /* if (prims[entry].iBound.contains(point)) */ |
511 | | - if (prims[entry].IsInsideObject(point, zVec, group_Z)) |
| 537 | + if (result != GroupModel::MAYBE_INSIDE) |
| 538 | + { |
| 539 | + if (group_Z < distance) |
512 | 540 | { |
513 | | - //minVol = pVol; |
514 | | - //hit = prims + entry; |
515 | | - if (group_Z < zDist) |
516 | | - { |
517 | | - zDist = group_Z; |
518 | | - hit = prims + entry; |
519 | | - } |
520 | | -#ifdef VMAP_DEBUG |
521 | | - GroupModel const& gm = prims[entry]; |
522 | | - printf("%10u %8X %7.3f, %7.3f, %7.3f | %7.3f, %7.3f, %7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(), |
523 | | - gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z, |
524 | | - gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z); |
525 | | -#endif |
| 541 | + distance = group_Z; |
| 542 | + hit[result] = &prims[entry]; |
| 543 | + return true; |
526 | 544 | } |
527 | | - //} |
528 | | - //std::cout << "trying to intersect '" << prims[entry].name << "'\n"; |
| 545 | + } |
| 546 | + else |
| 547 | + hit[result] = &prims[entry]; |
529 | 548 | } |
| 549 | + return false; |
| 550 | + } |
530 | 551 | }; |
531 | 552 |
|
532 | 553 | bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const |
533 | 554 | { |
534 | 555 | if (groupModels.empty()) |
535 | 556 | return false; |
536 | 557 |
|
537 | | - WModelAreaCallback callback(groupModels, down); |
538 | | - groupTree.intersectPoint(p, callback); |
539 | | - if (callback.hit != groupModels.end()) |
| 558 | + WModelAreaCallback callback(groupModels); |
| 559 | + G3D::Ray r(p - down * 0.1f, down); |
| 560 | + float zDist = groupTree.bound().extent().length(); |
| 561 | + groupTree.intersectRay(r, callback, zDist, false); |
| 562 | + if (callback.hit[GroupModel::INSIDE]) |
| 563 | + { |
| 564 | + info.rootId = RootWMOID; |
| 565 | + info.hitModel = callback.hit[GroupModel::INSIDE]; |
| 566 | + dist = zDist; |
| 567 | + return true; |
| 568 | + } |
| 569 | + |
| 570 | + // some group models don't have any floor to intersect with |
| 571 | + // so we should attempt to intersect with a model part below the group `p` is in (stored in GroupModel::ABOVE) |
| 572 | + // then find back where we originated from (GroupModel::MAYBE_INSIDE) |
| 573 | + if (callback.hit[GroupModel::MAYBE_INSIDE] && callback.hit[GroupModel::ABOVE]) |
540 | 574 | { |
541 | 575 | info.rootId = RootWMOID; |
542 | | - info.hitModel = &(*callback.hit); |
543 | | - dist = callback.zDist; |
| 576 | + info.hitModel = callback.hit[GroupModel::MAYBE_INSIDE]; |
| 577 | + dist = zDist; |
544 | 578 | return true; |
545 | 579 | } |
546 | 580 | return false; |
|
0 commit comments