2021-09-13 15:53:43 +03:00
//
// Created by Иван Ильин on 13.01.2021.
//
# include "World.h"
# include "utils/Log.h"
# include "Plane.h"
using namespace std ;
2021-10-17 10:21:10 +03:00
void World : : addBody ( std : : shared_ptr < RigidBody > body , const ObjectNameTag & tag ) {
_objects . emplace ( tag , body ) ;
Log : : log ( " World::addBody(): inserted body ' " + tag . str ( ) + " ' with " + std : : to_string ( _objects [ tag ] - > triangles ( ) . size ( ) ) + " tris. " ) ;
2021-09-13 15:53:43 +03:00
}
2021-10-17 10:21:10 +03:00
void World : : loadBody ( const ObjectNameTag & tag , const string & filename , const std : : string & materials , const Vec3D & scale ) {
_objects . emplace ( tag , std : : make_shared < RigidBody > ( Mesh ( filename , materials , scale ) ) ) ;
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-17 10:21:10 +03:00
std : : pair < Vec3D , ObjectNameTag > World : : rayCast ( const Vec3D & from , const Vec3D & to , const std : : string & tag ) {
2021-09-13 15:53:43 +03:00
2021-10-12 17:12:47 +03:00
std : : pair < Vec3D , string > result ;
std : : unique_ptr < Vec3D > point = std : : make_unique < Vec3D > ( ) ;
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-09-13 15:53:43 +03:00
2021-10-17 10:21:10 +03:00
for ( auto & [ name , body ] : _objects ) {
if ( ! tag . empty ( ) & & name . str ( ) . find ( tag ) = = std : : string : : npos )
2021-09-13 15:53:43 +03:00
continue ;
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-12 17:12:47 +03:00
point = std : : make_unique < Vec3D > ( intersection . first ) ;
2021-10-17 10:21:10 +03:00
bodyName = name . str ( ) ;
2021-09-13 15:53:43 +03:00
}
}
}
2021-10-17 10:21:10 +03:00
return { * point , ObjectNameTag ( bodyName ) } ;
2021-09-13 15:53:43 +03:00
}
2021-10-12 17:12:47 +03:00
void World : : loadMap ( const std : : string & filename , const std : : string & materials , const std : : string & name , const Vec3D & scale ) {
2021-09-13 15:53:43 +03:00
auto objs = Mesh : : LoadObjects ( filename , materials , scale ) ;
2021-10-09 13:41:12 +03:00
for ( unsigned i = 0 ; i < objs . size ( ) ; i + + ) {
2021-10-17 10:21:10 +03:00
ObjectNameTag meshName = ObjectNameTag ( name + " _ " + to_string ( i ) ) ;
2021-09-19 11:25:10 +03:00
addBody ( std : : make_shared < RigidBody > ( * objs [ i ] ) , meshName ) ;
2021-09-13 15:53:43 +03:00
}
}
2021-10-17 10:21:10 +03:00
void World : : removeBody ( const ObjectNameTag & tag ) {
if ( _objects . erase ( tag ) > 0 )
Log : : log ( " World::removeBody(): removed body ' " + tag . str ( ) + " ' " ) ;
2021-09-13 15:53:43 +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-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-17 10:21:10 +03:00
if ( _objects [ tag ] - > collisionCallBack ( ) ! = nullptr )
_objects [ tag ] - > collisionCallBack ( ) ( name , obj ) ;
2021-09-19 11:25:10 +03:00
}
}
}
}
}
void World : : update ( ) {
for ( auto & m : _objects ) {
m . second - > updatePhysicsState ( ) ;
checkCollision ( m . first ) ;
}
}
void World : : projectObjectsInCamera ( std : : shared_ptr < Camera > camera ) {
2021-10-17 10:21:10 +03:00
for ( auto & [ name , body ] : _objects )
camera - > project ( body ) ;
2021-09-19 11:25:10 +03:00
}
2021-10-17 10:21:10 +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-17 10:21:10 +03:00
return _objects . find ( tag ) - > second ;
2021-09-13 15:53:43 +03:00
}