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-09-19 11:25:10 +03:00
# include "physics/Solver.h"
2021-09-13 15:53:43 +03:00
using namespace std ;
2021-09-19 11:25:10 +03:00
void World : : addBody ( std : : shared_ptr < RigidBody > body , const string & name ) {
_objects . emplace ( name , body ) ;
2021-10-09 13:41:12 +03:00
Log : : log ( " World::addBody(): inserted body ' " + name + " ' with " + std : : to_string ( _objects [ name ] - > triangles ( ) . size ( ) ) + " tris. " ) ;
2021-09-13 15:53:43 +03:00
}
2021-10-12 17:12:47 +03:00
void World : : loadBody ( const string & name , const string & filename , const std : : string & materials , const Vec3D & scale ) {
2021-09-19 11:25:10 +03:00
_objects . emplace ( name , std : : make_shared < RigidBody > ( Mesh ( filename , materials , scale ) ) ) ;
2021-10-09 13:41:12 +03:00
Log : : log ( " World::loadBody(): inserted body from " + filename + " with title ' " + name + " ' with " + std : : to_string ( _objects [ name ] - > triangles ( ) . size ( ) ) + " tris. " ) ;
2021-09-13 15:53:43 +03:00
}
2021-10-12 17:12:47 +03:00
std : : pair < Vec3D , string > World : : rayCast ( const Vec3D & from , const Vec3D & to ) {
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 > ( ) ;
std : : string name ;
double minDistance = Consts : : RAY_CAST_MAX_DISTANCE ;
2021-09-13 15:53:43 +03:00
for ( auto & object : _objects ) {
2021-10-09 14:38:24 +03:00
if ( ( object . first . find ( " Player " ) ! = std : : string : : npos ) | | ( object . first . find ( " Bonus " ) ! = std : : string : : npos ) )
2021-09-13 15:53:43 +03:00
continue ;
for ( auto & tri : object . second - > triangles ( ) ) {
2021-10-12 17:12:47 +03:00
Triangle tri_translated ( tri [ 0 ] + object . second - > position ( ) . makePoint4D ( ) , tri [ 1 ] + object . second - > position ( ) . makePoint4D ( ) , tri [ 2 ] + object . second - > 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 ) ;
name = object . first ;
2021-09-13 15:53:43 +03:00
}
}
}
2021-10-12 17:12:47 +03:00
return { * point , name } ;
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-09-13 15:53:43 +03:00
string meshName = 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-09 13:41:12 +03:00
void World : : removeBody ( string name ) {
2021-09-13 15:53:43 +03:00
if ( _objects . erase ( name ) > 0 )
2021-10-09 13:41:12 +03:00
Log : : log ( " World::removeBody(): removed body ' " + name + " ' " ) ;
2021-09-13 15:53:43 +03:00
else
2021-10-09 13:41:12 +03:00
Log : : log ( " World::removeBody(): cannot remove body ' " + name + " ': body does not exist. " ) ;
2021-09-19 11:25:10 +03:00
}
void World : : checkCollision ( const std : : string & body ) {
if ( _objects [ body ] - > isCollision ( ) ) {
_objects [ body ] - > setInCollision ( false ) ;
2021-10-09 14:38:24 +03:00
for ( auto it = _objects . begin ( ) ; it ! = _objects . end ( ) ; ) {
auto obj = it - > second ;
std : : string name = it - > first ;
it + + ;
if ( name ! = body ) {
std : : pair < bool , Simplex > gjk = _objects [ body ] - > checkGJKCollision ( obj ) ;
2021-09-19 11:25:10 +03:00
if ( gjk . first ) {
2021-10-09 14:38:24 +03:00
if ( obj - > isCollider ( ) ) {
CollisionPoint epa = _objects [ body ] - > EPA ( gjk . second , obj ) ;
Solver : : solveCollision ( _objects [ body ] , obj , epa ) ;
2021-09-19 11:25:10 +03:00
}
if ( _objects [ body ] - > collisionCallBack ( ) ! = nullptr )
2021-10-09 14:38:24 +03:00
_objects [ body ] - > 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 ) {
for ( auto & m : _objects )
camera - > project ( m . second ) ;
}
std : : shared_ptr < RigidBody > World : : body ( const string & name ) {
if ( _objects . count ( name ) = = 0 )
2021-10-16 16:14:51 +03:00
return nullptr ;
2021-09-19 11:25:10 +03:00
return _objects . find ( name ) - > second ;
2021-09-13 15:53:43 +03:00
}