2021-09-13 15:53:43 +03:00
|
|
|
//
|
|
|
|
// Created by Иван Ильин on 13.01.2021.
|
|
|
|
//
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
#include <sstream>
|
|
|
|
#include <cmath>
|
|
|
|
|
2021-09-13 15:53:43 +03:00
|
|
|
#include "World.h"
|
|
|
|
#include "utils/Log.h"
|
|
|
|
#include "Plane.h"
|
2021-10-18 06:44:04 +03:00
|
|
|
#include "ResourceManager.h"
|
2021-09-13 15:53:43 +03:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2021-10-28 16:58:02 +03:00
|
|
|
void World::addBody(std::shared_ptr<RigidBody> body) {
|
|
|
|
_objects.emplace(body->name(), body);
|
2021-10-31 11:39:08 +03:00
|
|
|
Log::log("World::addBody(): inserted body '" + body->name().str() + "' with " +
|
|
|
|
std::to_string(_objects[body->name()]->triangles().size()) + " tris.");
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
void World::loadBody(const ObjectNameTag &tag, const string &filename, const Vec3D &scale) {
|
2021-10-28 16:58:02 +03:00
|
|
|
_objects.emplace(tag, std::make_shared<RigidBody>(Mesh(tag, filename, scale)));
|
2021-10-31 11:39:08 +03:00
|
|
|
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + tag.str() + "' with " +
|
|
|
|
std::to_string(_objects[tag]->triangles().size()) + " tris.");
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
IntersectionInformation World::rayCast(const Vec3D &from, const Vec3D &to, const std::string &skipTags) {
|
2021-09-13 15:53:43 +03:00
|
|
|
|
2021-10-22 19:42:32 +03:00
|
|
|
// make vector of tags, that we are going to escape
|
2021-10-31 11:39:08 +03:00
|
|
|
vector<std::string> tagsToSkip;
|
2021-10-22 19:42:32 +03:00
|
|
|
stringstream s(skipTags);
|
|
|
|
std::string t;
|
2021-10-29 18:41:07 +03:00
|
|
|
while (s >> t) {
|
|
|
|
tagsToSkip.push_back(t);
|
|
|
|
}
|
2021-10-22 19:42:32 +03:00
|
|
|
|
|
|
|
bool intersected = false;
|
2021-10-28 16:58:02 +03:00
|
|
|
Vec3D point{};
|
|
|
|
Triangle triangle;
|
2021-10-17 10:21:10 +03:00
|
|
|
std::string bodyName;
|
2021-10-12 17:12:47 +03:00
|
|
|
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
|
2021-10-22 19:42:32 +03:00
|
|
|
std::shared_ptr<RigidBody> intersectedBody = nullptr;
|
2021-09-13 15:53:43 +03:00
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
for (auto&[name, body] : _objects) {
|
2021-10-22 19:42:32 +03:00
|
|
|
|
2021-10-29 18:41:07 +03:00
|
|
|
bool escapeThisBody = false;
|
2021-10-31 11:39:08 +03:00
|
|
|
for (auto &escapeTag : tagsToSkip) {
|
2021-10-29 18:41:07 +03:00
|
|
|
if (name.str().find(escapeTag) != std::string::npos) {
|
|
|
|
escapeThisBody = true;
|
2021-10-29 23:44:37 +03:00
|
|
|
break;
|
2021-10-29 18:41:07 +03:00
|
|
|
}
|
|
|
|
}
|
2021-10-31 11:39:08 +03:00
|
|
|
if (escapeThisBody) {
|
2021-09-13 15:53:43 +03:00
|
|
|
continue;
|
2021-10-28 16:58:02 +03:00
|
|
|
}
|
2021-09-13 15:53:43 +03:00
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
for (auto &tri : body->triangles()) {
|
2021-10-30 00:20:48 +03:00
|
|
|
Matrix4x4 model = body->model();
|
2021-10-31 11:39:08 +03:00
|
|
|
Triangle tri_translated(model * tri[0], model * tri[1], model * tri[2]);
|
2021-09-13 15:53:43 +03:00
|
|
|
|
|
|
|
Plane plane(tri_translated);
|
|
|
|
auto intersection = plane.intersection(from, to);
|
|
|
|
double distance = (intersection.first - from).sqrAbs();
|
2021-10-31 11:39:08 +03:00
|
|
|
if (intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) {
|
2021-09-13 15:53:43 +03:00
|
|
|
minDistance = distance;
|
2021-10-28 16:58:02 +03:00
|
|
|
point = intersection.first;
|
|
|
|
triangle = tri_translated;
|
2021-10-17 10:21:10 +03:00
|
|
|
bodyName = name.str();
|
2021-10-22 19:42:32 +03:00
|
|
|
intersected = true;
|
|
|
|
intersectedBody = body;
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-31 11:39:08 +03:00
|
|
|
return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody,
|
|
|
|
intersected};
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
void World::loadMap(const std::string &filename, const Vec3D &scale) {
|
2021-10-18 09:21:09 +03:00
|
|
|
auto objs = ResourceManager::loadObjects(filename);
|
2021-10-31 11:39:08 +03:00
|
|
|
for (auto &i : objs) {
|
2021-10-28 16:58:02 +03:00
|
|
|
std::shared_ptr<RigidBody> obj = std::make_shared<RigidBody>(*i);
|
|
|
|
addBody(obj);
|
|
|
|
obj->scale(scale);
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
void World::removeBody(const ObjectNameTag &tag) {
|
|
|
|
if (_objects.erase(tag) > 0) {
|
2021-10-17 10:21:10 +03:00
|
|
|
Log::log("World::removeBody(): removed body '" + tag.str() + "'");
|
2021-10-28 16:58:02 +03:00
|
|
|
} else {
|
2021-10-17 10:21:10 +03:00
|
|
|
Log::log("World::removeBody(): cannot remove body '" + tag.str() + "': body does not exist.");
|
2021-10-28 16:58:02 +03:00
|
|
|
}
|
2021-09-19 11:25:10 +03:00
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
void World::checkCollision(const ObjectNameTag &tag) {
|
2021-11-03 22:57:48 +03:00
|
|
|
if (_objects[tag]->hasCollision()) {
|
2021-09-19 11:25:10 +03:00
|
|
|
|
2021-10-17 10:21:10 +03:00
|
|
|
_objects[tag]->setInCollision(false);
|
2021-09-19 11:25:10 +03:00
|
|
|
|
2021-10-09 14:38:24 +03:00
|
|
|
for (auto it = _objects.begin(); it != _objects.end();) {
|
|
|
|
auto obj = it->second;
|
2021-10-17 10:21:10 +03:00
|
|
|
ObjectNameTag name = it->first;
|
2021-10-09 14:38:24 +03:00
|
|
|
it++;
|
|
|
|
|
2021-11-03 22:57:48 +03:00
|
|
|
if ((name == tag) || !(obj->isCollider() || obj->isTrigger())) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::pair<bool, Simplex> gjk = _objects[tag]->checkGJKCollision(obj);
|
|
|
|
if (gjk.first) {
|
|
|
|
if (obj->isCollider()) {
|
|
|
|
CollisionPoint epa = _objects[tag]->EPA(gjk.second, obj);
|
|
|
|
_objects[tag]->solveCollision(epa);
|
|
|
|
}
|
|
|
|
if (_objects[tag]->collisionCallBack() != nullptr) {
|
|
|
|
_objects[tag]->collisionCallBack()(name, obj);
|
2021-09-19 11:25:10 +03:00
|
|
|
}
|
|
|
|
}
|
2021-11-03 22:57:48 +03:00
|
|
|
|
2021-09-19 11:25:10 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void World::update() {
|
|
|
|
for (auto &m : _objects) {
|
|
|
|
m.second->updatePhysicsState();
|
|
|
|
checkCollision(m.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-31 11:39:08 +03:00
|
|
|
std::shared_ptr<RigidBody> World::body(const ObjectNameTag &tag) {
|
|
|
|
if (_objects.count(tag) == 0) {
|
2021-10-16 16:14:51 +03:00
|
|
|
return nullptr;
|
2021-10-28 16:58:02 +03:00
|
|
|
}
|
2021-10-17 10:21:10 +03:00
|
|
|
return _objects.find(tag)->second;
|
2021-09-13 15:53:43 +03:00
|
|
|
}
|