2021-09-13 15:53:43 +03:00
//
// Created by Иван Ильин on 13.01.2021.
//
# include "World.h"
# include "utils/Log.h"
# include "Plane.h"
2021-10-18 06:44:04 +03:00
# include "ResourceManager.h"
2021-10-22 19:42:32 +03:00
# include <sstream>
# include <cmath>
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 ) ;
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-17 20:52:21 +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-17 10:21:10 +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-22 19:42:32 +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-29 18:41:07 +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-17 10:21:10 +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 ;
for ( auto & escapeTag : tagsToSkip ) {
if ( name . str ( ) . find ( escapeTag ) ! = std : : string : : npos ) {
escapeThisBody = true ;
}
}
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-17 10:21:10 +03:00
for ( auto & tri : body - > triangles ( ) ) {
Triangle tri_translated ( tri [ 0 ] + body - > position ( ) . makePoint4D ( ) , tri [ 1 ] + body - > position ( ) . makePoint4D ( ) , tri [ 2 ] + body - > position ( ) . makePoint4D ( ) ) ;
2021-09-13 15:53:43 +03:00
Plane plane ( tri_translated ) ;
auto intersection = plane . intersection ( from , to ) ;
double distance = ( intersection . first - from ) . sqrAbs ( ) ;
if ( intersection . second > 0 & & distance < minDistance & & tri_translated . isPointInside ( intersection . first ) ) {
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-28 16:58:02 +03:00
return IntersectionInformation { point , sqrt ( minDistance ) , triangle , ObjectNameTag ( bodyName ) , intersectedBody , intersected } ;
2021-09-13 15:53:43 +03:00
}
2021-10-17 20:52:21 +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-28 16:58:02 +03:00
for ( auto & i : objs ) {
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-17 10:21:10 +03:00
void World : : removeBody ( const ObjectNameTag & tag ) {
2021-10-28 16:58:02 +03:00
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-17 10:21:10 +03:00
void World : : checkCollision ( const ObjectNameTag & tag ) {
if ( _objects [ tag ] - > isCollision ( ) ) {
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-10-17 10:21:10 +03:00
if ( name ! = tag ) {
std : : pair < bool , Simplex > gjk = _objects [ tag ] - > checkGJKCollision ( obj ) ;
2021-09-19 11:25:10 +03:00
if ( gjk . first ) {
2021-10-09 14:38:24 +03:00
if ( obj - > isCollider ( ) ) {
2021-10-17 10:21:10 +03:00
CollisionPoint epa = _objects [ tag ] - > EPA ( gjk . second , obj ) ;
_objects [ tag ] - > solveCollision ( epa ) ;
2021-09-19 11:25:10 +03:00
}
2021-10-28 16:58:02 +03:00
if ( _objects [ tag ] - > collisionCallBack ( ) ! = nullptr ) {
2021-10-17 10:21:10 +03:00
_objects [ tag ] - > collisionCallBack ( ) ( name , obj ) ;
2021-10-28 16:58:02 +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-17 10:21:10 +03:00
std : : shared_ptr < RigidBody > World : : body ( const ObjectNameTag & tag ) {
2021-10-28 16:58:02 +03:00
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
}