Point4D & Triangle now are completely immutable.
- Deleted operator= for Point4D and Triangle - Add Vec3D & Vec2D to substitute Point4D in cases where we dont need 4 dimensions. Vec3D & Vec2D are immutable. - Small refactoring of EPA & GJK in RigidBody.cppmaster
parent
423e6d0d35
commit
d3684f8aa6
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include "Bonus.h"
|
#include "Bonus.h"
|
||||||
|
|
||||||
Bonus::Bonus(const std::string &bonusName, const std::string &filename, const std::string &materials, const Point4D &scale) {
|
Bonus::Bonus(const std::string &bonusName, const std::string &filename, const std::string &materials, const Vec3D &scale) {
|
||||||
_name = bonusName;
|
_name = bonusName;
|
||||||
loadObj(filename, materials, scale);
|
loadObj(filename, materials, scale);
|
||||||
setCollider(false);
|
setCollider(false);
|
||||||
|
|
2
Bonus.h
2
Bonus.h
|
@ -12,7 +12,7 @@ class Bonus : public RigidBody {
|
||||||
protected:
|
protected:
|
||||||
std::string _name;
|
std::string _name;
|
||||||
public:
|
public:
|
||||||
explicit Bonus(const std::string &bonusName, const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
|
explicit Bonus(const std::string &bonusName, const std::string& filename, const std::string &materials = "", const Vec3D& scale = Vec3D{1, 1, 1});
|
||||||
|
|
||||||
[[nodiscard]] std::string name() const { return _name; }
|
[[nodiscard]] std::string name() const { return _name; }
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,10 +34,10 @@ add_executable(shooter
|
||||||
# 3d engine:
|
# 3d engine:
|
||||||
engine/utils/Time.h
|
engine/utils/Time.h
|
||||||
engine/utils/Time.cpp
|
engine/utils/Time.cpp
|
||||||
engine/utils/Point4D.h
|
engine/Point4D.h
|
||||||
engine/utils/Point4D.cpp
|
engine/Point4D.cpp
|
||||||
engine/utils/Matrix4x4.h
|
engine/Matrix4x4.h
|
||||||
engine/utils/Matrix4x4.cpp
|
engine/Matrix4x4.cpp
|
||||||
engine/Triangle.h
|
engine/Triangle.h
|
||||||
engine/Triangle.cpp
|
engine/Triangle.cpp
|
||||||
engine/Mesh.h
|
engine/Mesh.h
|
||||||
|
@ -94,7 +94,7 @@ add_executable(shooter
|
||||||
engine/network/UDPSocket.h
|
engine/network/UDPSocket.h
|
||||||
engine/network/config.h
|
engine/network/config.h
|
||||||
engine/animation/AFunction.h
|
engine/animation/AFunction.h
|
||||||
engine/Consts.h)
|
engine/Consts.h engine/Vec3D.cpp engine/Vec3D.h engine/Vec2D.cpp engine/Vec2D.h ShooterConsts.h)
|
||||||
|
|
||||||
if(APPLE OR UNIX)
|
if(APPLE OR UNIX)
|
||||||
include_directories(/usr/local/include)
|
include_directories(/usr/local/include)
|
||||||
|
|
25
Client.cpp
25
Client.cpp
|
@ -28,7 +28,7 @@ void Client::processInit(sf::Packet& packet) {
|
||||||
if(targetId != _socket.ownId()) {
|
if(targetId != _socket.ownId()) {
|
||||||
spawnPlayer(targetId);
|
spawnPlayer(targetId);
|
||||||
|
|
||||||
_players[targetId]->translateToPoint(Point4D{ buf[0], buf[1], buf[2]});
|
_players[targetId]->translateToPoint(Vec3D{ buf[0], buf[1], buf[2]});
|
||||||
_players[targetId]->setHealth(buf[3]);
|
_players[targetId]->setHealth(buf[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,11 +41,11 @@ void Client::processUpdate(sf::Packet& packet) {
|
||||||
while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5]) {
|
while (packet >> targetId >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4] >> buf[5]) {
|
||||||
if (_players.count(targetId)) {
|
if (_players.count(targetId)) {
|
||||||
std::string name = "Player_" + std::to_string(targetId);
|
std::string name = "Player_" + std::to_string(targetId);
|
||||||
_players[targetId]->translateToPoint(Point4D{buf[0], buf[1], buf[2]});
|
_players[targetId]->translateToPoint(Vec3D{buf[0], buf[1], buf[2]});
|
||||||
_players[targetId]->setHealth(buf[3]);
|
_players[targetId]->setHealth(buf[3]);
|
||||||
_players[targetId]->rotateToAngle(Point4D{0, buf[4], 0});
|
_players[targetId]->rotateToAngle(Vec3D{0, buf[4], 0});
|
||||||
|
|
||||||
_players[targetId]->attached("head")->rotate(Matrix4x4::RotationY(buf[4]) * Point4D{1, 0, 0}, buf[5] - _players[targetId]->headAngle());
|
_players[targetId]->attached("head")->rotate(Matrix4x4::RotationY(buf[4]) * Vec3D{1, 0, 0}, buf[5] - _players[targetId]->headAngle());
|
||||||
|
|
||||||
_players[targetId]->setHeadAngle(buf[5]);
|
_players[targetId]->setHeadAngle(buf[5]);
|
||||||
} else if (targetId == _socket.ownId()) {
|
} else if (targetId == _socket.ownId()) {
|
||||||
|
@ -74,7 +74,6 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
|
||||||
sf::Uint16 buffId[2];
|
sf::Uint16 buffId[2];
|
||||||
double dbuff[10];
|
double dbuff[10];
|
||||||
std::string tmp, tmp2;
|
std::string tmp, tmp2;
|
||||||
Point4D p1, p2;
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MsgType::Kill:
|
case MsgType::Kill:
|
||||||
|
@ -82,7 +81,7 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
|
||||||
if(buffId[0] == _socket.ownId()) {
|
if(buffId[0] == _socket.ownId()) {
|
||||||
_player->addDeath();
|
_player->addDeath();
|
||||||
// respawn
|
// respawn
|
||||||
_player->translateToPoint(Point4D{50.0*(-1 + 2.0*(double)rand()/RAND_MAX),30.0*(double)rand()/RAND_MAX,50.0*(-1 + 2.0*(double)rand()/RAND_MAX)});
|
_player->translateToPoint(Vec3D{50.0*(-1 + 2.0*(double)rand()/RAND_MAX),30.0*(double)rand()/RAND_MAX,50.0*(-1 + 2.0*(double)rand()/RAND_MAX)});
|
||||||
_player->playDeath();
|
_player->playDeath();
|
||||||
_player->initWeapons();
|
_player->initWeapons();
|
||||||
_player->setFullAbility();
|
_player->setFullAbility();
|
||||||
|
@ -99,23 +98,21 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) {
|
||||||
case MsgType::FireTrace:
|
case MsgType::FireTrace:
|
||||||
packet >> dbuff[0] >> dbuff[1] >> dbuff[2] >> dbuff[3] >> dbuff[4] >> dbuff[5];
|
packet >> dbuff[0] >> dbuff[1] >> dbuff[2] >> dbuff[3] >> dbuff[4] >> dbuff[5];
|
||||||
|
|
||||||
p1 = Point4D(dbuff[0], dbuff[1], dbuff[2]);
|
|
||||||
p2 = Point4D(dbuff[3], dbuff[4], dbuff[5]);
|
|
||||||
if(_addFireTraceCallBack != nullptr)
|
if(_addFireTraceCallBack != nullptr)
|
||||||
_addFireTraceCallBack(p1, p2);
|
_addFireTraceCallBack(Vec3D(dbuff[0], dbuff[1], dbuff[2]), Vec3D(dbuff[3], dbuff[4], dbuff[5]));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MsgType::InitBonuses:
|
case MsgType::InitBonuses:
|
||||||
while (packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2]) {
|
while (packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2]) {
|
||||||
if(_addBonusCallBack != nullptr)
|
if(_addBonusCallBack != nullptr)
|
||||||
_addBonusCallBack(tmp, Point4D(dbuff[0], dbuff[1], dbuff[2]));
|
_addBonusCallBack(tmp, Vec3D(dbuff[0], dbuff[1], dbuff[2]));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MsgType::AddBonus:
|
case MsgType::AddBonus:
|
||||||
packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2];
|
packet >> tmp >> dbuff[0] >> dbuff[1] >> dbuff[2];
|
||||||
if(_addBonusCallBack != nullptr)
|
if(_addBonusCallBack != nullptr)
|
||||||
_addBonusCallBack(tmp, Point4D(dbuff[0], dbuff[1], dbuff[2]));
|
_addBonusCallBack(tmp, Vec3D(dbuff[0], dbuff[1], dbuff[2]));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MsgType::RemoveBonus:
|
case MsgType::RemoveBonus:
|
||||||
|
@ -141,7 +138,7 @@ void Client::damagePlayer(sf::Uint16 targetId, double damage) {
|
||||||
Log::log("Client: damagePlayer " + std::to_string(targetId) + " ( -" + std::to_string(damage) + "hp )");
|
Log::log("Client: damagePlayer " + std::to_string(targetId) + " ( -" + std::to_string(damage) + "hp )");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::addTrace(const Point4D& from, const Point4D& to) {
|
void Client::addTrace(const Vec3D& from, const Vec3D& to) {
|
||||||
sf::Packet packet;
|
sf::Packet packet;
|
||||||
|
|
||||||
packet << MsgType::FireTrace << from.x() << from.y() << from.z() << to.x() << to.y() << to.z();
|
packet << MsgType::FireTrace << from.x() << from.y() << from.z() << to.x() << to.y() << to.z();
|
||||||
|
@ -170,11 +167,11 @@ void Client::setRemovePlayerCallBack(std::function<void(sf::Uint16)> remove) {
|
||||||
_removePlayerCallBack = std::move(remove);
|
_removePlayerCallBack = std::move(remove);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::setAddFireTraceCallBack(std::function<void(const Point4D &, const Point4D &)> addTrace) {
|
void Client::setAddFireTraceCallBack(std::function<void(const Vec3D &, const Vec3D &)> addTrace) {
|
||||||
_addFireTraceCallBack = std::move(addTrace);
|
_addFireTraceCallBack = std::move(addTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::setAddBonusCallBack(std::function<void(const std::string &, const Point4D &)> addBonus) {
|
void Client::setAddBonusCallBack(std::function<void(const std::string &, const Vec3D &)> addBonus) {
|
||||||
_addBonusCallBack = std::move(addBonus);
|
_addBonusCallBack = std::move(addBonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
Client.h
10
Client.h
|
@ -17,8 +17,8 @@ private:
|
||||||
|
|
||||||
std::function<void(sf::Uint16)> _spawnPlayerCallBack;
|
std::function<void(sf::Uint16)> _spawnPlayerCallBack;
|
||||||
std::function<void(sf::Uint16)> _removePlayerCallBack;
|
std::function<void(sf::Uint16)> _removePlayerCallBack;
|
||||||
std::function<void(const Point4D&, const Point4D&)> _addFireTraceCallBack;
|
std::function<void(const Vec3D&, const Vec3D&)> _addFireTraceCallBack;
|
||||||
std::function<void(const std::string&, const Point4D&)> _addBonusCallBack;
|
std::function<void(const std::string&, const Vec3D&)> _addBonusCallBack;
|
||||||
std::function<void(const std::string&)> _removeBonusCallBack;
|
std::function<void(const std::string&)> _removeBonusCallBack;
|
||||||
public:
|
public:
|
||||||
explicit Client(std::shared_ptr<Player> player) : _player(player){};
|
explicit Client(std::shared_ptr<Player> player) : _player(player){};
|
||||||
|
@ -27,8 +27,8 @@ public:
|
||||||
|
|
||||||
void setSpawnPlayerCallBack(std::function<void(sf::Uint16)> spawn);
|
void setSpawnPlayerCallBack(std::function<void(sf::Uint16)> spawn);
|
||||||
void setRemovePlayerCallBack(std::function<void(sf::Uint16)> remove);
|
void setRemovePlayerCallBack(std::function<void(sf::Uint16)> remove);
|
||||||
void setAddFireTraceCallBack(std::function<void(const Point4D&, const Point4D&)> addTrace);
|
void setAddFireTraceCallBack(std::function<void(const Vec3D&, const Vec3D&)> addTrace);
|
||||||
void setAddBonusCallBack(std::function<void(const std::string&, const Point4D&)> addBonus);
|
void setAddBonusCallBack(std::function<void(const std::string&, const Vec3D&)> addBonus);
|
||||||
void setRemoveBonusCallBack(std::function<void(const std::string&)> removeBonus);
|
void setRemoveBonusCallBack(std::function<void(const std::string&)> removeBonus);
|
||||||
|
|
||||||
void processInit(sf::Packet& packet) override;
|
void processInit(sf::Packet& packet) override;
|
||||||
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
void takeBonus(const std::string& bonusName);
|
void takeBonus(const std::string& bonusName);
|
||||||
|
|
||||||
void addTrace(const Point4D& from, const Point4D& to);
|
void addTrace(const Vec3D& from, const Vec3D& to);
|
||||||
|
|
||||||
void addPlayer(sf::Uint16 id, std::shared_ptr<Player> player);
|
void addPlayer(sf::Uint16 id, std::shared_ptr<Player> player);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "engine/ResourceManager.h"
|
#include "engine/ResourceManager.h"
|
||||||
#include "engine/utils/Log.h"
|
#include "engine/utils/Log.h"
|
||||||
|
|
||||||
void Player::rotateWeaponsRelativePoint(const Point4D& point4D, const Point4D& v, double val) {
|
void Player::rotateWeaponsRelativePoint(const Vec3D& point4D, const Vec3D& v, double val) {
|
||||||
for(auto& weapon : _weapons)
|
for(auto& weapon : _weapons)
|
||||||
weapon->rotateRelativePoint(point4D, v, val);
|
weapon->rotateRelativePoint(point4D, v, val);
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ void Player::addWeapon(std::shared_ptr<Weapon> weapon) {
|
||||||
attach(weapon, weapon->name());
|
attach(weapon, weapon->name());
|
||||||
|
|
||||||
_weapons.back()->translate(position());
|
_weapons.back()->translate(position());
|
||||||
_weapons.back()->rotateRelativePoint(position() + Point4D{0, 1.8, 0}, Point4D{0, 1, 0}, _angle.y());
|
_weapons.back()->rotateRelativePoint(position() + Vec3D{0, 1.8, 0}, Vec3D{0, 1, 0}, _angle->y());
|
||||||
_weapons.back()->rotateRelativePoint(position() + Point4D{0, 1.8, 0}, left(), headAngle());
|
_weapons.back()->rotateRelativePoint(position() + Vec3D{0, 1.8, 0}, left(), headAngle());
|
||||||
|
|
||||||
_weapons.back()->setAddTraceCallBack(_addTraceCallBack);
|
_weapons.back()->setAddTraceCallBack(_addTraceCallBack);
|
||||||
}
|
}
|
||||||
|
|
17
Player.h
17
Player.h
|
@ -42,17 +42,17 @@ private:
|
||||||
size_t _selectedWeapon = 0;
|
size_t _selectedWeapon = 0;
|
||||||
|
|
||||||
std::function<void(sf::Uint16 targetId, double)> _damagePlayerCallBack;
|
std::function<void(sf::Uint16 targetId, double)> _damagePlayerCallBack;
|
||||||
std::function<void(const Point4D&, const Point4D&)> _addTraceCallBack;
|
std::function<void(const Vec3D&, const Vec3D&)> _addTraceCallBack;
|
||||||
std::function<void(const std::string&)> _takeBonusCallBack;
|
std::function<void(const std::string&)> _takeBonusCallBack;
|
||||||
|
|
||||||
std::function<void(std::shared_ptr<Weapon>)> _addWeaponCallBack;
|
std::function<void(std::shared_ptr<Weapon>)> _addWeaponCallBack;
|
||||||
std::function<void(std::shared_ptr<Weapon>)> _removeWeaponCallBack;
|
std::function<void(std::shared_ptr<Weapon>)> _removeWeaponCallBack;
|
||||||
|
|
||||||
std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> _rayCastFunction;
|
std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> _rayCastFunction;
|
||||||
public:
|
public:
|
||||||
Player() {
|
Player() {
|
||||||
loadObj("obj/cube.obj", "", Point4D{0.5, 1.9, 0.5});
|
loadObj("obj/cube.obj", "", Vec3D{0.5, 1.9, 0.5});
|
||||||
setAcceleration(Point4D{0, -_g, 0});
|
setAcceleration(Vec3D{0, -_g, 0});
|
||||||
setCollision(true);
|
setCollision(true);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
setColor({240, 168, 168});
|
setColor({240, 168, 168});
|
||||||
|
@ -68,6 +68,9 @@ public:
|
||||||
void setHealth(double h) {
|
void setHealth(double h) {
|
||||||
_health = h;
|
_health = h;
|
||||||
}
|
}
|
||||||
|
void setAbility(double a) {
|
||||||
|
_ability = a;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] double health() const { return _health; }
|
[[nodiscard]] double health() const { return _health; }
|
||||||
[[nodiscard]] double ability() const { return _ability; }
|
[[nodiscard]] double ability() const { return _ability; }
|
||||||
|
@ -93,7 +96,7 @@ public:
|
||||||
void fire();
|
void fire();
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
void rotateWeaponsRelativePoint(const Point4D& point4D, const Point4D& v, double val);
|
void rotateWeaponsRelativePoint(const Vec3D& point, const Vec3D& v, double val);
|
||||||
|
|
||||||
[[nodiscard]] int kills() const {return _kills;}
|
[[nodiscard]] int kills() const {return _kills;}
|
||||||
[[nodiscard]] int deaths() const {return _deaths;}
|
[[nodiscard]] int deaths() const {return _deaths;}
|
||||||
|
@ -107,7 +110,7 @@ public:
|
||||||
void setDamagePlayerCallBack(std::function<void(sf::Uint16 targetId, double)> hit) {
|
void setDamagePlayerCallBack(std::function<void(sf::Uint16 targetId, double)> hit) {
|
||||||
_damagePlayerCallBack = std::move(hit);
|
_damagePlayerCallBack = std::move(hit);
|
||||||
}
|
}
|
||||||
void setAddTraceCallBack(std::function<void(const Point4D&, const Point4D&)> add) {
|
void setAddTraceCallBack(std::function<void(const Vec3D&, const Vec3D&)> add) {
|
||||||
_addTraceCallBack = std::move(add);
|
_addTraceCallBack = std::move(add);
|
||||||
}
|
}
|
||||||
void setTakeBonusCallBack(std::function<void(const std::string&)> take) {
|
void setTakeBonusCallBack(std::function<void(const std::string&)> take) {
|
||||||
|
@ -119,7 +122,7 @@ public:
|
||||||
void setRemoveWeaponCallBack(std::function<void(std::shared_ptr<Weapon>)> removeWeapon) {
|
void setRemoveWeaponCallBack(std::function<void(std::shared_ptr<Weapon>)> removeWeapon) {
|
||||||
_removeWeaponCallBack = std::move(removeWeapon);
|
_removeWeaponCallBack = std::move(removeWeapon);
|
||||||
}
|
}
|
||||||
void setRayCastFunction(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction) {
|
void setRayCastFunction(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction) {
|
||||||
_rayCastFunction = std::move(rayCastFunction);
|
_rayCastFunction = std::move(rayCastFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,21 +51,21 @@ void PlayerController::update() {
|
||||||
Timeline::animate("camera_hor_oscil", new AWait(0));
|
Timeline::animate("camera_hor_oscil", new AWait(0));
|
||||||
Timeline::animate("camera_hor_oscil", new ATranslate(camera, camera->left() / 6, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_hor_oscil", new ATranslate(camera, camera->left() / 6, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
|
|
||||||
Timeline::animate("camera_vert_oscil", new ATranslate(camera, -Point4D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_vert_oscil", new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
Timeline::animate("camera_vert_oscil", new AWait(0));
|
Timeline::animate("camera_vert_oscil", new AWait(0));
|
||||||
Timeline::animate("camera_vert_oscil", new ATranslate(camera, Point4D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_vert_oscil", new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
Timeline::animate("camera_vert_oscil", new AWait(0));
|
Timeline::animate("camera_vert_oscil", new AWait(0));
|
||||||
Timeline::animate("camera_vert_oscil", new ATranslate(camera, -Point4D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_vert_oscil", new ATranslate(camera, -Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
Timeline::animate("camera_vert_oscil", new AWait(0));
|
Timeline::animate("camera_vert_oscil", new AWait(0));
|
||||||
Timeline::animate("camera_vert_oscil", new ATranslate(camera, Point4D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_vert_oscil", new ATranslate(camera, Vec3D{0, 1, 0} / 12, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
|
|
||||||
Timeline::animate("camera_init", new ATranslateToPoint( camera, _player->position() + Point4D{0, 1.8, 0}, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_init", new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.3, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
}
|
}
|
||||||
} else if(inRunning_old && !_inRunning) {
|
} else if(inRunning_old && !_inRunning) {
|
||||||
Timeline::deleteAnimationList("camera_hor_oscil");
|
Timeline::deleteAnimationList("camera_hor_oscil");
|
||||||
Timeline::deleteAnimationList("camera_vert_oscil");
|
Timeline::deleteAnimationList("camera_vert_oscil");
|
||||||
Timeline::deleteAnimationList("camera_init");
|
Timeline::deleteAnimationList("camera_init");
|
||||||
Timeline::animate("camera_init", new ATranslateToPoint( camera, _player->position() + Point4D{0, 1.8, 0}, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
Timeline::animate("camera_init", new ATranslateToPoint( camera, _player->position() + Vec3D{0, 1.8, 0}, 0.15, Animation::LoopOut::None, Animation::InterpolationType::cos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Left and right
|
// Left and right
|
||||||
|
@ -73,26 +73,26 @@ void PlayerController::update() {
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::A)) {
|
if (Keyboard::isKeyPressed(sf::Keyboard::A)) {
|
||||||
_player->translate(_player->left() * Time::deltaTime() * _walkSpeed * coeff);
|
_player->translate(_player->left() * Time::deltaTime() * _walkSpeed * coeff);
|
||||||
if(_player->inCollision())
|
if(_player->inCollision())
|
||||||
_player->setVelocity(Point4D{0,0,0});
|
_player->setVelocity(Vec3D{0,0,0});
|
||||||
}
|
}
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::D)) {
|
if (Keyboard::isKeyPressed(sf::Keyboard::D)) {
|
||||||
_player->translate(-_player->left() * Time::deltaTime() * _walkSpeed * coeff);
|
_player->translate(-_player->left() * Time::deltaTime() * _walkSpeed * coeff);
|
||||||
if(_player->inCollision())
|
if(_player->inCollision())
|
||||||
_player->setVelocity(Point4D{0,0,0});
|
_player->setVelocity(Vec3D{0,0,0});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward and backward
|
// Forward and backward
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
if (Keyboard::isKeyPressed(sf::Keyboard::W)) {
|
||||||
_player->translate(_player->lookAt() * Time::deltaTime() * _walkSpeed * coeff);
|
_player->translate(_player->lookAt() * Time::deltaTime() * _walkSpeed * coeff);
|
||||||
if(_player->inCollision())
|
if(_player->inCollision())
|
||||||
_player->setVelocity(Point4D{0,0,0});
|
_player->setVelocity(Vec3D{0,0,0});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
if (Keyboard::isKeyPressed(sf::Keyboard::S)) {
|
||||||
_player->translate(-_player->lookAt() * Time::deltaTime() * _walkSpeed * coeff);
|
_player->translate(-_player->lookAt() * Time::deltaTime() * _walkSpeed * coeff);
|
||||||
|
|
||||||
if(_player->inCollision())
|
if(_player->inCollision())
|
||||||
_player->setVelocity(Point4D{0,0,0});
|
_player->setVelocity(Vec3D{0,0,0});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_player->ability() > 0 && !_isInSlowMo && Keyboard::isKeyPressed(sf::Keyboard::LShift)) {
|
if (_player->ability() > 0 && !_isInSlowMo && Keyboard::isKeyPressed(sf::Keyboard::LShift)) {
|
||||||
|
@ -111,24 +111,23 @@ void PlayerController::update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) {
|
if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) {
|
||||||
|
|
||||||
// if we just want to jump, we have to add particular speed
|
// if we just want to jump, we have to add particular speed
|
||||||
if (!_isSliding)
|
if (!_isSliding)
|
||||||
_player->addVelocity(Point4D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * _jumpHeight) * coeff, 0 });
|
_player->addVelocity(Vec3D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * _jumpHeight) * coeff, 0 });
|
||||||
// if we want to slide, we have to add speed * 60/fps to make it independent on frame rate
|
// if we want to slide, we have to add speed * 60/fps to make it independent on frame rate
|
||||||
else
|
else
|
||||||
_player->addVelocity(Point4D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * _jumpHeight) * coeff * 60.0 / Time::fps(), 0 });
|
_player->addVelocity(Vec3D{ 0, std::abs(_player->collisionNormal().y()) * sqrt(2 * -_player->acceleration().y() * _jumpHeight) * coeff * 60.0 / Time::fps(), 0 });
|
||||||
|
|
||||||
_player->translate(Point4D{ 0, Time::deltaTime() * _walkSpeed * 2 * coeff * 60.0 / Time::fps(), 0 });
|
_player->translate(Vec3D{ 0, Time::deltaTime() * _walkSpeed * 2 * coeff * 60.0 / Time::fps(), 0 });
|
||||||
_isSliding = true;
|
_isSliding = true;
|
||||||
} else {
|
} else {
|
||||||
_isSliding = false;
|
_isSliding = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mouse movement
|
// Mouse movement
|
||||||
Point4D displacement = _mouse->getMouseDisplacement();
|
Vec2D displacement = _mouse->getMouseDisplacement();
|
||||||
|
|
||||||
_player->rotate(Point4D{0, -displacement.x() / 1000.0, 0});
|
_player->rotate(Vec3D{0, -displacement.x() / 1000.0, 0});
|
||||||
_player->setVelocity(Matrix4x4::RotationY(-displacement.x() / 1000.0) * _player->velocity());
|
_player->setVelocity(Matrix4x4::RotationY(-displacement.x() / 1000.0) * _player->velocity());
|
||||||
|
|
||||||
double rotationLeft = displacement.y() / 1000.0;
|
double rotationLeft = displacement.y() / 1000.0;
|
||||||
|
@ -140,7 +139,7 @@ void PlayerController::update() {
|
||||||
rotationLeft = -Consts::PI / 2 - _player->headAngle();
|
rotationLeft = -Consts::PI / 2 - _player->headAngle();
|
||||||
|
|
||||||
_player->setHeadAngle(_player->headAngle() + rotationLeft);
|
_player->setHeadAngle(_player->headAngle() + rotationLeft);
|
||||||
_player->rotateWeaponsRelativePoint(_player->position() + Point4D{0, 1.8, 0}, _player->left(), rotationLeft);
|
_player->rotateWeaponsRelativePoint(_player->position() + Vec3D{0, 1.8, 0}, _player->left(), rotationLeft);
|
||||||
|
|
||||||
if (_keyboard->isKeyTapped(sf::Keyboard::Right) || _keyboard->isKeyTapped(sf::Keyboard::E)) {
|
if (_keyboard->isKeyTapped(sf::Keyboard::Right) || _keyboard->isKeyTapped(sf::Keyboard::E)) {
|
||||||
_player->nextWeapon();
|
_player->nextWeapon();
|
||||||
|
|
10
Server.cpp
10
Server.cpp
|
@ -9,14 +9,12 @@ void Server::broadcast() {
|
||||||
sf::Packet updatePacket;
|
sf::Packet updatePacket;
|
||||||
updatePacket << MsgType::Update;
|
updatePacket << MsgType::Update;
|
||||||
|
|
||||||
for (auto& player : _players)
|
for (auto& player : _players) {
|
||||||
{
|
|
||||||
//player.second->setHealth(player.second->health() + (Time::time() - _lastBroadcast)/100);
|
//player.second->setHealth(player.second->health() + (Time::time() - _lastBroadcast)/100);
|
||||||
updatePacket << player.first << player.second->position().x() << player.second->position().y() << player.second->position().z() << player.second->health() << player.second->angle().y() << player.second->headAngle();
|
updatePacket << player.first << player.second->position().x() << player.second->position().y() << player.second->position().z() << player.second->health() << player.second->angle().y() << player.second->headAngle();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& player : _players)
|
for (auto& player : _players) {
|
||||||
{
|
|
||||||
_socket.send(updatePacket, player.first);
|
_socket.send(updatePacket, player.first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +51,8 @@ void Server::processClientUpdate(sf::Uint16 senderId, sf::Packet& packet) {
|
||||||
double buf[5];
|
double buf[5];
|
||||||
|
|
||||||
packet >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4];
|
packet >> buf[0] >> buf[1] >> buf[2] >> buf[3] >> buf[4];
|
||||||
_players.at(senderId)->translateToPoint(Point4D{ buf[0], buf[1], buf[2] });
|
_players.at(senderId)->translateToPoint(Vec3D{ buf[0], buf[1], buf[2] });
|
||||||
_players.at(senderId)->rotateToAngle(Point4D{0, buf[3], 0});
|
_players.at(senderId)->rotateToAngle(Vec3D{0, buf[3], 0});
|
||||||
_players.at(senderId)->setHeadAngle(buf[4]);
|
_players.at(senderId)->setHeadAngle(buf[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
40
Shooter.cpp
40
Shooter.cpp
|
@ -56,8 +56,8 @@ void Shooter::InitNetwork()
|
||||||
|
|
||||||
client->setSpawnPlayerCallBack([this](sf::Uint16 id){ spawnPlayer(id); });
|
client->setSpawnPlayerCallBack([this](sf::Uint16 id){ spawnPlayer(id); });
|
||||||
client->setRemovePlayerCallBack([this](sf::Uint16 id){ removePlayer(id); });
|
client->setRemovePlayerCallBack([this](sf::Uint16 id){ removePlayer(id); });
|
||||||
client->setAddFireTraceCallBack([this](const Point4D& from, const Point4D& to){ addFireTrace(from, to); });
|
client->setAddFireTraceCallBack([this](const Vec3D& from, const Vec3D& to){ addFireTrace(from, to); });
|
||||||
client->setAddBonusCallBack([this](const std::string& bonusName, const Point4D& position){ addBonus(bonusName, position); });
|
client->setAddBonusCallBack([this](const std::string& bonusName, const Vec3D& position){ addBonus(bonusName, position); });
|
||||||
client->setRemoveBonusCallBack([this](const std::string& bonusName){ removeBonus(bonusName); });
|
client->setRemoveBonusCallBack([this](const std::string& bonusName){ removeBonus(bonusName); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,25 +68,25 @@ void Shooter::start() {
|
||||||
|
|
||||||
mouse->setMouseCursorVisible(true);
|
mouse->setMouseCursorVisible(true);
|
||||||
|
|
||||||
world->loadMap("maps/map1.obj", "maps/materials.txt", "map", Point4D{5, 5, 5});
|
world->loadMap("maps/map1.obj", "maps/materials.txt", "map", Vec3D{5, 5, 5});
|
||||||
|
|
||||||
player = std::make_shared<Player>();
|
player = std::make_shared<Player>();
|
||||||
playerController = std::make_shared<PlayerController>(player, keyboard, mouse);
|
playerController = std::make_shared<PlayerController>(player, keyboard, mouse);
|
||||||
|
|
||||||
player->setAddTraceCallBack([this](const Point4D& from, const Point4D& to){ client->addTrace(from, to); addFireTrace(from, to); });
|
player->setAddTraceCallBack([this](const Vec3D& from, const Vec3D& to){ client->addTrace(from, to); addFireTrace(from, to); });
|
||||||
player->setDamagePlayerCallBack([this] (sf::Uint16 targetId, double damage) { client->damagePlayer(targetId, damage); });
|
player->setDamagePlayerCallBack([this] (sf::Uint16 targetId, double damage) { client->damagePlayer(targetId, damage); });
|
||||||
player->setRayCastFunction([this](const Point4D& from, const Point4D& to) { return world->rayCast(from, to); });
|
player->setRayCastFunction([this](const Vec3D& from, const Vec3D& to) { return world->rayCast(from, to); });
|
||||||
player->setTakeBonusCallBack([this] (const string& bonusName) { client->takeBonus(bonusName); });
|
player->setTakeBonusCallBack([this] (const string& bonusName) { client->takeBonus(bonusName); });
|
||||||
|
|
||||||
player->setAddWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ addWeapon(weapon); });
|
player->setAddWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ addWeapon(weapon); });
|
||||||
player->setRemoveWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ removeWeapon(weapon); });
|
player->setRemoveWeaponCallBack([this](std::shared_ptr<Weapon> weapon){ removeWeapon(weapon); });
|
||||||
|
|
||||||
player->initWeapons();
|
player->initWeapons();
|
||||||
|
|
||||||
camera->translateToPoint(player->position() + Point4D{0, 1.8, 0});
|
camera->translateToPoint(player->position() + Vec3D{0, 1.8, 0});
|
||||||
player->attach(camera, "camera");
|
player->attach(camera, "camera");
|
||||||
|
|
||||||
world->addBody(player, "Player");
|
world->addBody(player, "Player");
|
||||||
player->translate(Point4D{0, 10, 0});
|
player->translate(Vec3D{0, 10, 0});
|
||||||
|
|
||||||
client = std::make_shared<Client>(player);
|
client = std::make_shared<Client>(player);
|
||||||
server = std::make_shared<Server>();
|
server = std::make_shared<Server>();
|
||||||
|
@ -96,7 +96,7 @@ void Shooter::start() {
|
||||||
mainMenu.setBackgroundTexture("textures/back.png", 1.1, 1.1, screen->width(), screen->height());
|
mainMenu.setBackgroundTexture("textures/back.png", 1.1, 1.1, screen->width(), screen->height());
|
||||||
|
|
||||||
mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); }, "Play", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); }, "Play", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
||||||
mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Point4D{0, 0, 0}); this->player->setVelocity({}); this->play(); }, "Respawn", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Vec3D{0, 0, 0}); this->player->setVelocity({}); this->play(); }, "Respawn", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
||||||
|
|
||||||
mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, "textures/gui.png", {0, 66}, {0, 86}, {0, 46}, "engine/fonts/Roboto-Medium.ttf", {255, 255, 255}, "sound/click.ogg");
|
||||||
|
|
||||||
|
@ -207,22 +207,22 @@ void Shooter::spawnPlayer(sf::Uint16 id) {
|
||||||
client->addPlayer(id, newPlayer);
|
client->addPlayer(id, newPlayer);
|
||||||
world->addBody(newPlayer, name);
|
world->addBody(newPlayer, name);
|
||||||
newPlayer->setVisible(true);
|
newPlayer->setVisible(true);
|
||||||
newPlayer->setAcceleration(Point4D{0, 0, 0});
|
newPlayer->setAcceleration(Vec3D{0, 0, 0});
|
||||||
|
|
||||||
// add head and other stuff:
|
// add head and other stuff:
|
||||||
world->loadBody(name + "_head", "obj/cube.obj", "", Point4D{0.7, 0.7, 0.7});
|
world->loadBody(name + "_head", "obj/cube.obj", "", Vec3D{0.7, 0.7, 0.7});
|
||||||
world->body(name + "_head")->translate(Point4D{0, 2, 0});
|
world->body(name + "_head")->translate(Vec3D{0, 2, 0});
|
||||||
world->body(name + "_head")->setCollider(false);
|
world->body(name + "_head")->setCollider(false);
|
||||||
newPlayer->attach(world->body(name + "_head"), "head");
|
newPlayer->attach(world->body(name + "_head"), "head");
|
||||||
|
|
||||||
world->loadBody(name + "_eye1", "obj/cube.obj", "", Point4D{0.2, 0.2, 0.05});
|
world->loadBody(name + "_eye1", "obj/cube.obj", "", Vec3D{0.2, 0.2, 0.05});
|
||||||
world->body(name + "_eye1")->translate(Point4D{0.3, 2.1, 0.7});
|
world->body(name + "_eye1")->translate(Vec3D{0.3, 2.1, 0.7});
|
||||||
world->body(name + "_eye1")->setCollider(false);
|
world->body(name + "_eye1")->setCollider(false);
|
||||||
world->body(name + "_eye1")->setColor({147, 159, 255});
|
world->body(name + "_eye1")->setColor({147, 159, 255});
|
||||||
world->body(name + "_head")->attach(world->body(name + "_eye1"), "eye1");
|
world->body(name + "_head")->attach(world->body(name + "_eye1"), "eye1");
|
||||||
|
|
||||||
world->loadBody(name + "_eye2", "obj/cube.obj", "", Point4D{0.2, 0.2, 0.05});
|
world->loadBody(name + "_eye2", "obj/cube.obj", "", Vec3D{0.2, 0.2, 0.05});
|
||||||
world->body(name + "_eye2")->translate(Point4D{-0.3, 2.1, 0.7});
|
world->body(name + "_eye2")->translate(Vec3D{-0.3, 2.1, 0.7});
|
||||||
world->body(name + "_eye2")->setCollider(false);
|
world->body(name + "_eye2")->setCollider(false);
|
||||||
world->body(name + "_eye2")->setColor({147, 159, 255});
|
world->body(name + "_eye2")->setColor({147, 159, 255});
|
||||||
world->body(name + "_head")->attach(world->body(name + "_eye2"), "eye2");
|
world->body(name + "_head")->attach(world->body(name + "_eye2"), "eye2");
|
||||||
|
@ -236,7 +236,7 @@ void Shooter::removePlayer(sf::Uint16 id) {
|
||||||
world->removeBody(name + "_eye2");
|
world->removeBody(name + "_eye2");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shooter::addFireTrace(const Point4D &from, const Point4D &to) {
|
void Shooter::addFireTrace(const Vec3D &from, const Vec3D &to) {
|
||||||
std::string traceName = "Client_fireTraces_" + std::to_string(fireTraces++);
|
std::string traceName = "Client_fireTraces_" + std::to_string(fireTraces++);
|
||||||
world->addBody(std::make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), traceName);
|
world->addBody(std::make_shared<RigidBody>(Mesh::LineTo(from, to, 0.05)), traceName);
|
||||||
world->body(traceName)->setCollider(false);
|
world->body(traceName)->setCollider(false);
|
||||||
|
@ -249,11 +249,11 @@ void Shooter::deleteFireTrace(const std::string& traceName) {
|
||||||
world->removeBody(traceName);
|
world->removeBody(traceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shooter::addBonus(const string &bonusName, const Point4D &position) {
|
void Shooter::addBonus(const string &bonusName, const Vec3D &position) {
|
||||||
std::string name = bonusName.substr(6, bonusName.size()-3-5);
|
std::string name = bonusName.substr(6, bonusName.size()-3-5);
|
||||||
world->addBody(std::make_shared<Bonus>(bonusName, "obj/" + name + ".obj", "obj/" + name + "_mat.txt", Point4D{3, 3, 3}), bonusName);
|
world->addBody(std::make_shared<Bonus>(bonusName, "obj/" + name + ".obj", "obj/" + name + "_mat.txt", Vec3D{3, 3, 3}), bonusName);
|
||||||
world->body(bonusName)->translateToPoint(position);
|
world->body(bonusName)->translateToPoint(position);
|
||||||
Timeline::animate(bonusName + "_rotation", new ARotate(world->body(bonusName), Point4D{0, 2*Consts::PI, 0}, 4, Animation::LoopOut::Continue, Animation::InterpolationType::linear));
|
Timeline::animate(bonusName + "_rotation", new ARotate(world->body(bonusName), Vec3D{0, 2*Consts::PI, 0}, 4, Animation::LoopOut::Continue, Animation::InterpolationType::linear));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shooter::removeBonus(const string &bonusName) {
|
void Shooter::removeBonus(const string &bonusName) {
|
||||||
|
|
|
@ -43,9 +43,9 @@ private:
|
||||||
|
|
||||||
void spawnPlayer(sf::Uint16 id);
|
void spawnPlayer(sf::Uint16 id);
|
||||||
void removePlayer(sf::Uint16 id);
|
void removePlayer(sf::Uint16 id);
|
||||||
void addFireTrace(const Point4D& from, const Point4D& to);
|
void addFireTrace(const Vec3D& from, const Vec3D& to);
|
||||||
void deleteFireTrace(const std::string& traceName);
|
void deleteFireTrace(const std::string& traceName);
|
||||||
void addBonus(const std::string& bonusName, const Point4D& position);
|
void addBonus(const std::string& bonusName, const Vec3D& position);
|
||||||
void removeBonus(const std::string& bonusName);
|
void removeBonus(const std::string& bonusName);
|
||||||
void addWeapon(std::shared_ptr<Weapon> weapon);
|
void addWeapon(std::shared_ptr<Weapon> weapon);
|
||||||
void removeWeapon(std::shared_ptr<Weapon> weapon);
|
void removeWeapon(std::shared_ptr<Weapon> weapon);
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
//
|
||||||
|
// Created by Иван Ильин on 10.10.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHOOTER_SHOOTERCONSTS_H
|
||||||
|
#define SHOOTER_SHOOTERCONSTS_H
|
||||||
|
|
||||||
|
namespace ShooterConsts {
|
||||||
|
const double GRAVITY = 35;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SHOOTER_SHOOTERCONSTS_H
|
|
@ -8,11 +8,11 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "Consts.h"
|
#include "Consts.h"
|
||||||
|
|
||||||
std::vector<Triangle> &Camera::project(std::shared_ptr<Mesh> mesh) {
|
std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mesh) {
|
||||||
|
|
||||||
if(!_ready) {
|
if(!_ready) {
|
||||||
Log::log("Camera::project(): cannot project _tris without camera initialization ( Camera::init() ) ");
|
Log::log("Camera::project(): cannot project _tris without camera initialization ( Camera::init() ) ");
|
||||||
return this->_triangles;
|
return _triangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!mesh->isVisible())
|
if(!mesh->isVisible())
|
||||||
|
@ -24,37 +24,36 @@ std::vector<Triangle> &Camera::project(std::shared_ptr<Mesh> mesh) {
|
||||||
|
|
||||||
// We don't want to waste time re-allocating memory every time
|
// We don't want to waste time re-allocating memory every time
|
||||||
std::vector<Triangle> clippedTriangles, tempBuffer;
|
std::vector<Triangle> clippedTriangles, tempBuffer;
|
||||||
|
|
||||||
for(auto& t : mesh->triangles()) {
|
for(auto& t : mesh->triangles()) {
|
||||||
|
|
||||||
double dot = t.norm().dot((mesh->position() + t[0] - _position).normalized());
|
|
||||||
|
double dot = t.norm().dot((mesh->position() + Vec3D(t[0]) - position()).normalized());
|
||||||
|
|
||||||
if(dot > 0)
|
if(dot > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Triangle clipped[2];
|
|
||||||
// It needs to be cleared because it's reused through iterations. Usually it doesn't free memory.
|
// It needs to be cleared because it's reused through iterations. Usually it doesn't free memory.
|
||||||
clippedTriangles.clear();
|
clippedTriangles.clear();
|
||||||
|
tempBuffer.clear();
|
||||||
|
|
||||||
// In the beginning we need to to translate drawTriangle from world coordinate to our camera system:
|
// In the beginning we need to to translate triangle from world coordinate to our camera system:
|
||||||
// After that we apply clipping for all planes from _clipPlanes
|
// After that we apply clipping for all planes from _clipPlanes
|
||||||
clippedTriangles.emplace_back(t * VM);
|
clippedTriangles.emplace_back(t * VM);
|
||||||
for(auto& plane : _clipPlanes)
|
for(auto& plane : _clipPlanes)
|
||||||
{
|
{
|
||||||
while(!clippedTriangles.empty())
|
while(!clippedTriangles.empty())
|
||||||
{
|
{
|
||||||
clipped[0] = clippedTriangles.back();
|
std::vector<Triangle> clipResult = plane.clip(clippedTriangles.back());
|
||||||
clipped[1] = clipped[0];
|
|
||||||
clippedTriangles.pop_back();
|
clippedTriangles.pop_back();
|
||||||
int additional = plane.clip(clipped[0], clipped[1]);
|
for(auto & i : clipResult)
|
||||||
|
tempBuffer.emplace_back(i);
|
||||||
for(int i = 0; i < additional; i++)
|
|
||||||
tempBuffer.emplace_back(clipped[i]);
|
|
||||||
}
|
}
|
||||||
clippedTriangles.swap(tempBuffer);
|
clippedTriangles.swap(tempBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& clippedTriangle : clippedTriangles) {
|
for(auto& clipped : clippedTriangles) {
|
||||||
sf::Color color = clippedTriangle.color();
|
sf::Color color = clipped.color();
|
||||||
sf::Color ambientColor = sf::Color((sf::Uint8)(color.r * (0.3 * std::abs(dot) + 0.7)),
|
sf::Color ambientColor = sf::Color((sf::Uint8)(color.r * (0.3 * std::abs(dot) + 0.7)),
|
||||||
(sf::Uint8)(color.g * (0.3 * std::abs(dot) + 0.7)),
|
(sf::Uint8)(color.g * (0.3 * std::abs(dot) + 0.7)),
|
||||||
(sf::Uint8)(color.b * (0.3 * std::abs(dot) + 0.7)),
|
(sf::Uint8)(color.b * (0.3 * std::abs(dot) + 0.7)),
|
||||||
|
@ -62,14 +61,14 @@ std::vector<Triangle> &Camera::project(std::shared_ptr<Mesh> mesh) {
|
||||||
|
|
||||||
// Finally its time to project our clipped colored drawTriangle from 3D -> 2D
|
// Finally its time to project our clipped colored drawTriangle from 3D -> 2D
|
||||||
// and transform it's coordinate to screen space (in pixels):
|
// and transform it's coordinate to screen space (in pixels):
|
||||||
clippedTriangle = clippedTriangle * _SP;
|
Triangle clippedProjected = clipped * _SP;
|
||||||
|
|
||||||
clippedTriangle = Triangle(clippedTriangle[0] / clippedTriangle[0].w(),
|
Triangle clippedProjectedNormalized = Triangle(clippedProjected[0] / clippedProjected[0].w(),
|
||||||
clippedTriangle[1] / clippedTriangle[1].w(),
|
clippedProjected[1] / clippedProjected[1].w(),
|
||||||
clippedTriangle[2] / clippedTriangle[2].w(),
|
clippedProjected[2] / clippedProjected[2].w(),
|
||||||
ambientColor);
|
ambientColor);
|
||||||
|
|
||||||
_triangles.emplace_back(clippedTriangle);
|
_triangles.emplace_back(std::make_shared<Triangle>(clippedProjectedNormalized));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,28 +86,28 @@ void Camera::init(int width, int height, double fov, double ZNear, double ZFar)
|
||||||
|
|
||||||
// This is planes for clipping _tris.
|
// This is planes for clipping _tris.
|
||||||
// Motivation: we are not interest in _tris that we cannot see.
|
// Motivation: we are not interest in _tris that we cannot see.
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{0, 0, 1}, Point4D{0, 0, ZNear})); // near plane
|
_clipPlanes.emplace_back(Plane(Vec3D{0, 0, 1}, Vec3D{0, 0, ZNear})); // near plane
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{0, 0, -1}, Point4D{0, 0, ZFar})); // far plane
|
_clipPlanes.emplace_back(Plane(Vec3D{0, 0, -1}, Vec3D{0, 0, ZFar})); // far plane
|
||||||
|
|
||||||
double thetta1 = Consts::PI*fov*0.5/180.0;
|
double thetta1 = Consts::PI*fov*0.5/180.0;
|
||||||
double thetta2 = atan(_aspect * tan(thetta1));
|
double thetta2 = atan(_aspect * tan(thetta1));
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{-cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // left plane
|
_clipPlanes.emplace_back(Plane(Vec3D{-cos(thetta2), 0, sin(thetta2)}, Vec3D{0, 0, 0})); // left plane
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{cos(thetta2), 0, sin(thetta2)}, Point4D{0, 0, 0})); // right plane
|
_clipPlanes.emplace_back(Plane(Vec3D{cos(thetta2), 0, sin(thetta2)}, Vec3D{0, 0, 0})); // right plane
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{0, cos(thetta1), sin(thetta1)}, Point4D{0, 0, 0})); // down plane
|
_clipPlanes.emplace_back(Plane(Vec3D{0, cos(thetta1), sin(thetta1)}, Vec3D{0, 0, 0})); // down plane
|
||||||
_clipPlanes.emplace_back(Plane(Point4D{0, -cos(thetta1), sin(thetta1)}, Point4D{0, 0, 0})); // up plane
|
_clipPlanes.emplace_back(Plane(Vec3D{0, -cos(thetta1), sin(thetta1)}, Vec3D{0, 0, 0})); // up plane
|
||||||
|
|
||||||
_ready = true;
|
_ready = true;
|
||||||
Log::log("Camera::init(): camera successfully initialized.");
|
Log::log("Camera::init(): camera successfully initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Triangle> &Camera::sorted() {
|
std::vector<std::shared_ptr<Triangle>> Camera::sorted() {
|
||||||
|
|
||||||
// Sort _tris from _back to front
|
// Sort _tris from _back to front
|
||||||
// This is some replacement for Z-buffer
|
// This is some replacement for Z-buffer
|
||||||
std::sort(_triangles.begin(), _triangles.end(), [](Triangle &t1, Triangle &t2)
|
std::sort(_triangles.begin(), _triangles.end(), [](std::shared_ptr<Triangle> &t1, std::shared_ptr<Triangle> &t2)
|
||||||
{
|
{
|
||||||
std::vector<double> v_z1({t1[0].z(), t1[1].z(), t1[2].z()});
|
std::vector<double> v_z1({(*t1)[0].z(), (*t1)[1].z(), (*t1)[2].z()});
|
||||||
std::vector<double> v_z2({t2[0].z(), t2[1].z(), t2[2].z()});
|
std::vector<double> v_z2({(*t2)[0].z(), (*t2)[1].z(), (*t2)[2].z()});
|
||||||
|
|
||||||
std::sort(v_z1.begin(), v_z1.end());
|
std::sort(v_z1.begin(), v_z1.end());
|
||||||
std::sort(v_z2.begin(), v_z2.end());
|
std::sort(v_z2.begin(), v_z2.end());
|
||||||
|
@ -127,5 +126,5 @@ void Camera::clear() {
|
||||||
// That is like preparation for new camera shot: we need to set
|
// That is like preparation for new camera shot: we need to set
|
||||||
// the position of camera and insert new cartridge for photo.
|
// the position of camera and insert new cartridge for photo.
|
||||||
_triangles.clear();
|
_triangles.clear();
|
||||||
_V = Matrix4x4::View(_left, _up, _lookAt, _position);
|
_V = Matrix4x4::View(left(), up(), lookAt(), position());
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ private:
|
||||||
// To accelerate calculations we can use precalculated matrix that does not chance
|
// To accelerate calculations we can use precalculated matrix that does not chance
|
||||||
Matrix4x4 _SP; // screen-space-projections matrix
|
Matrix4x4 _SP; // screen-space-projections matrix
|
||||||
|
|
||||||
std::vector<Triangle> _triangles{};
|
std::vector<std::shared_ptr<Triangle>> _triangles{};
|
||||||
std::vector<Plane> _clipPlanes{};
|
std::vector<Plane> _clipPlanes{};
|
||||||
|
|
||||||
bool _ready = false;
|
bool _ready = false;
|
||||||
|
@ -30,12 +30,12 @@ public:
|
||||||
|
|
||||||
void init(int width, int height, double fov = 110.0, double ZNear = 0.1, double ZFar = 5000.0);
|
void init(int width, int height, double fov = 110.0, double ZNear = 0.1, double ZFar = 5000.0);
|
||||||
|
|
||||||
std::vector<Triangle>& project(std::shared_ptr<Mesh> mesh);
|
std::vector<std::shared_ptr<Triangle>> project(std::shared_ptr<Mesh> mesh);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
[[nodiscard]] int buffSize() const { return _triangles.size(); }
|
[[nodiscard]] int buffSize() const { return _triangles.size(); }
|
||||||
std::vector<Triangle>& sorted();
|
std::vector<std::shared_ptr<Triangle>> sorted();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
|
|
||||||
namespace Consts {
|
namespace Consts {
|
||||||
const double PI = 3.14159265358979323846264338327950288;
|
const double PI = 3.14159265358979323846264338327950288;
|
||||||
|
const double EPS = 0.000001;
|
||||||
|
|
||||||
|
const int GJK_MAX_ITERATIONS = 50;
|
||||||
|
const double EPA_EPS = 0.0001;
|
||||||
|
|
||||||
|
const double RAY_CAST_MAX_DISTANCE = 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //SHOOTER_CONSTS_H
|
#endif //SHOOTER_CONSTS_H
|
||||||
|
|
|
@ -55,7 +55,7 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name,
|
||||||
|
|
||||||
// draw projected body
|
// draw projected body
|
||||||
for (auto &t : camera->sorted())
|
for (auto &t : camera->sorted())
|
||||||
screen->drawTriangle(t);
|
screen->drawTriangle(*t);
|
||||||
|
|
||||||
_triPerSec = camera->buffSize() * Time::fps();
|
_triPerSec = camera->buffSize() * Time::fps();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "../Consts.h"
|
#include "Consts.h"
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::operator*(const Matrix4x4 &matrix4X4) const {
|
Matrix4x4 Matrix4x4::operator*(const Matrix4x4 &matrix4X4) const {
|
||||||
Matrix4x4 result = Matrix4x4::Zero();
|
Matrix4x4 result = Matrix4x4::Zero();
|
||||||
|
@ -27,6 +27,14 @@ Point4D Matrix4x4::operator*(const Point4D &point4D) const {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3D Matrix4x4::operator*(const Vec3D &vec) const {
|
||||||
|
return Vec3D(
|
||||||
|
_arr[0][0] * vec.x() + _arr[0][1] * vec.y() + _arr[0][2] * vec.z(),
|
||||||
|
_arr[1][0] * vec.x() + _arr[1][1] * vec.y() + _arr[1][2] * vec.z(),
|
||||||
|
_arr[2][0] * vec.x() + _arr[2][1] * vec.y() + _arr[2][2] * vec.z()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Identity() {
|
Matrix4x4 Matrix4x4::Identity() {
|
||||||
Matrix4x4 result;
|
Matrix4x4 result;
|
||||||
|
|
||||||
|
@ -54,7 +62,7 @@ Matrix4x4 Matrix4x4::Zero() {
|
||||||
return Matrix4x4::Constant(0);
|
return Matrix4x4::Constant(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Scale(const Point4D& factor) {
|
Matrix4x4 Matrix4x4::Scale(const Vec3D& factor) {
|
||||||
Matrix4x4 s{};
|
Matrix4x4 s{};
|
||||||
s._arr[0][0] = factor.x();
|
s._arr[0][0] = factor.x();
|
||||||
s._arr[1][1] = factor.y();
|
s._arr[1][1] = factor.y();
|
||||||
|
@ -64,14 +72,8 @@ Matrix4x4 Matrix4x4::Scale(const Point4D& factor) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Translation(const Point4D& v) {
|
Matrix4x4 Matrix4x4::Translation(const Vec3D& v) {
|
||||||
Matrix4x4 t{};
|
Matrix4x4 t{};
|
||||||
/*
|
|
||||||
* ( 1 0 0 dx )(_x) (_x + dx)
|
|
||||||
* ( 0 1 0 dy )(_y) = (_y + dy)
|
|
||||||
* ( 0 0 1 dz )(z) (z + dz)
|
|
||||||
* ( 0 0 0 1 )(1) ( 1 )
|
|
||||||
*/
|
|
||||||
|
|
||||||
t._arr[0][0] = 1.0;
|
t._arr[0][0] = 1.0;
|
||||||
t._arr[1][1] = 1.0;
|
t._arr[1][1] = 1.0;
|
||||||
|
@ -129,25 +131,25 @@ Matrix4x4 Matrix4x4::RotationZ(double rz) {
|
||||||
return Rz;
|
return Rz;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Rotation(const Point4D& r) {
|
Matrix4x4 Matrix4x4::Rotation(const Vec3D& r) {
|
||||||
return RotationX(r.x()) * RotationY(r.y()) * RotationZ(r.z());
|
return RotationX(r.x()) * RotationY(r.y()) * RotationZ(r.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Rotation(Point4D v, double rv) {
|
Matrix4x4 Matrix4x4::Rotation(const Vec3D& v, double rv) {
|
||||||
Matrix4x4 Rv{};
|
Matrix4x4 Rv{};
|
||||||
v = v.normalized();
|
Vec3D nv(v.normalized());
|
||||||
|
|
||||||
Rv._arr[0][0] = cos(rv) + (1.0 - cos(rv))*v.x()*v.x();
|
Rv._arr[0][0] = cos(rv) + (1.0 - cos(rv))*nv.x()*nv.x();
|
||||||
Rv._arr[0][1] = (1.0 - cos(rv))*v.x()*v.y() - sin(rv)*v.z();
|
Rv._arr[0][1] = (1.0 - cos(rv))*nv.x()*nv.y() - sin(rv)*nv.z();
|
||||||
Rv._arr[0][2] = (1.0 - cos(rv))*v.x()*v.z() + sin(rv)*v.y();
|
Rv._arr[0][2] = (1.0 - cos(rv))*nv.x()*nv.z() + sin(rv)*nv.y();
|
||||||
|
|
||||||
Rv._arr[1][0] = (1.0 - cos(rv))*v.x()*v.y() + sin(rv)*v.z();
|
Rv._arr[1][0] = (1.0 - cos(rv))*nv.x()*nv.y() + sin(rv)*nv.z();
|
||||||
Rv._arr[1][1] = cos(rv) + (1.0 - cos(rv))*v.y()*v.y();
|
Rv._arr[1][1] = cos(rv) + (1.0 - cos(rv))*nv.y()*nv.y();
|
||||||
Rv._arr[1][2] = (1.0 - cos(rv))*v.y()*v.z() - sin(rv)*v.x();
|
Rv._arr[1][2] = (1.0 - cos(rv))*nv.y()*nv.z() - sin(rv)*nv.x();
|
||||||
|
|
||||||
Rv._arr[2][0] = (1.0 - cos(rv))*v.z()*v.x() - sin(rv)*v.y();
|
Rv._arr[2][0] = (1.0 - cos(rv))*nv.z()*nv.x() - sin(rv)*nv.y();
|
||||||
Rv._arr[2][1] = (1.0 - cos(rv))*v.z()*v.y() + sin(rv)*v.x();
|
Rv._arr[2][1] = (1.0 - cos(rv))*nv.z()*nv.y() + sin(rv)*nv.x();
|
||||||
Rv._arr[2][2] = cos(rv) + (1.0 - cos(rv))*v.z()*v.z();
|
Rv._arr[2][2] = cos(rv) + (1.0 - cos(rv))*nv.z()*nv.z();
|
||||||
|
|
||||||
Rv._arr[3][3] = 1.0;
|
Rv._arr[3][3] = 1.0;
|
||||||
|
|
||||||
|
@ -181,22 +183,22 @@ Matrix4x4 Matrix4x4::ScreenSpace(int width, int height) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::View(const Point4D &left, const Point4D &up, const Point4D &lookAt, const Point4D &eye) {
|
Matrix4x4 Matrix4x4::View(const Vec3D &left, const Vec3D &up, const Vec3D &lookAt, const Vec3D &eye) {
|
||||||
Matrix4x4 V = Zero();
|
Matrix4x4 V = Zero();
|
||||||
|
|
||||||
V._arr[0][0] = left[0];
|
V._arr[0][0] = left.x();
|
||||||
V._arr[0][1] = left[1];
|
V._arr[0][1] = left.y();
|
||||||
V._arr[0][2] = left[2];
|
V._arr[0][2] = left.z();
|
||||||
V._arr[0][3] = -eye.dot(left);
|
V._arr[0][3] = -eye.dot(left);
|
||||||
|
|
||||||
V._arr[1][0] = up[0];
|
V._arr[1][0] = up.x();
|
||||||
V._arr[1][1] = up[1];
|
V._arr[1][1] = up.y();
|
||||||
V._arr[1][2] = up[2];
|
V._arr[1][2] = up.z();
|
||||||
V._arr[1][3] = -eye.dot(up);
|
V._arr[1][3] = -eye.dot(up);
|
||||||
|
|
||||||
V._arr[2][0] = lookAt[0];
|
V._arr[2][0] = lookAt.x();
|
||||||
V._arr[2][1] = lookAt[1];
|
V._arr[2][1] = lookAt.y();
|
||||||
V._arr[2][2] = lookAt[2];
|
V._arr[2][2] = lookAt.z();
|
||||||
V._arr[2][3] = -eye.dot(lookAt);
|
V._arr[2][3] = -eye.dot(lookAt);
|
||||||
|
|
||||||
V._arr[3][3] = 1.0;
|
V._arr[3][3] = 1.0;
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include "Point4D.h"
|
#include "Point4D.h"
|
||||||
|
#include "Vec3D.h"
|
||||||
|
|
||||||
class Matrix4x4 {
|
class Matrix4x4 {
|
||||||
private:
|
private:
|
||||||
|
@ -18,21 +19,22 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4& matrix4X4) const;
|
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4& matrix4X4) const;
|
||||||
[[nodiscard]] Point4D operator*(const Point4D& point4D) const;
|
[[nodiscard]] Point4D operator*(const Point4D& point4D) const;
|
||||||
|
[[nodiscard]] Vec3D operator*(const Vec3D& vec) const;
|
||||||
|
|
||||||
// Any useful matrix (static methods)
|
// Any useful matrix (static methods)
|
||||||
Matrix4x4 static Identity();
|
Matrix4x4 static Identity();
|
||||||
Matrix4x4 static Zero();
|
Matrix4x4 static Zero();
|
||||||
Matrix4x4 static Constant (double value);
|
Matrix4x4 static Constant (double value);
|
||||||
|
|
||||||
Matrix4x4 static Scale(const Point4D& factor);
|
Matrix4x4 static Scale(const Vec3D& factor);
|
||||||
Matrix4x4 static Translation(const Point4D& v);
|
Matrix4x4 static Translation(const Vec3D& v);
|
||||||
Matrix4x4 static Rotation(const Point4D& r);
|
Matrix4x4 static Rotation(const Vec3D& r);
|
||||||
Matrix4x4 static RotationX (double rx);
|
Matrix4x4 static RotationX (double rx);
|
||||||
Matrix4x4 static RotationY (double ry);
|
Matrix4x4 static RotationY (double ry);
|
||||||
Matrix4x4 static RotationZ (double rz);
|
Matrix4x4 static RotationZ (double rz);
|
||||||
Matrix4x4 static Rotation (Point4D v, double rv);
|
Matrix4x4 static Rotation (const Vec3D& v, double rv);
|
||||||
|
|
||||||
Matrix4x4 static View(const Point4D& left, const Point4D& up, const Point4D& lookAt, const Point4D& eye);
|
Matrix4x4 static View(const Vec3D &left, const Vec3D &up, const Vec3D &lookAt, const Vec3D &eye);
|
||||||
Matrix4x4 static Projection (double fov = 90.0, double aspect = 1.0, double ZNear = 1.0, double ZFar = 10.0);
|
Matrix4x4 static Projection (double fov = 90.0, double aspect = 1.0, double ZNear = 1.0, double ZFar = 10.0);
|
||||||
Matrix4x4 static ScreenSpace (int width, int height);
|
Matrix4x4 static ScreenSpace (int width, int height);
|
||||||
};
|
};
|
|
@ -12,13 +12,16 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) {
|
Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) {
|
||||||
for (auto& t : _tris)
|
std::vector<Triangle> newTriangles;
|
||||||
t = t * matrix4X4;
|
for(auto &t : _tris) {
|
||||||
|
newTriangles.emplace_back(t * matrix4X4);
|
||||||
|
}
|
||||||
|
setTriangles(newTriangles);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh &Mesh::loadObj(const std::string& filename, const std::string &materials, const Point4D& scale) {
|
Mesh &Mesh::loadObj(const std::string& filename, const std::string &materials, const Vec3D& scale) {
|
||||||
|
|
||||||
auto objects = Mesh::LoadObjects(filename, materials, scale);
|
auto objects = Mesh::LoadObjects(filename, materials, scale);
|
||||||
for(auto& obj : objects) {
|
for(auto& obj : objects) {
|
||||||
|
@ -29,61 +32,54 @@ Mesh &Mesh::loadObj(const std::string& filename, const std::string &materials, c
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::Mesh(const std::string& filename, const std::string &materials, const Point4D& scale){
|
Mesh::Mesh(const std::string& filename, const std::string &materials, const Vec3D& scale){
|
||||||
loadObj(filename, materials, scale);
|
loadObj(filename, materials, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::Mesh(const vector<Triangle> &tries){
|
Mesh::Mesh(const vector<Triangle> &tries) : _tris(tries) {
|
||||||
_tris = tries;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh::Mesh(const Mesh& mesh) {
|
|
||||||
*this = mesh;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh Mesh::Obj(const std::string& filename) {
|
Mesh Mesh::Obj(const std::string& filename) {
|
||||||
return Mesh(filename);
|
return Mesh(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::rotate(const Point4D &r) {
|
void Mesh::rotate(const Vec3D &r) {
|
||||||
Object::rotate(r);
|
Object::rotate(r);
|
||||||
*this *= Matrix4x4::Rotation(r);
|
*this *= Matrix4x4::Rotation(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::rotate(const Point4D &v, double r) {
|
void Mesh::rotate(const Vec3D &v, double r) {
|
||||||
Object::rotate(v, r);
|
Object::rotate(v, r);
|
||||||
*this *= Matrix4x4::Rotation(v, r);
|
*this *= Matrix4x4::Rotation(v, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::scale(const Point4D &s) {
|
void Mesh::scale(const Vec3D &s) {
|
||||||
Object::scale(s);
|
Object::scale(s);
|
||||||
*this *= Matrix4x4::Scale(s);
|
*this *= Matrix4x4::Scale(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh &Mesh::operator=(const Mesh &mesh) {
|
void Mesh::rotateRelativePoint(const Vec3D &s, const Vec3D &r) {
|
||||||
_tris = mesh._tris;
|
|
||||||
_position = mesh._position;
|
|
||||||
_color = mesh._color;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &r) {
|
|
||||||
Object::rotateRelativePoint(s, r);
|
Object::rotateRelativePoint(s, r);
|
||||||
*this *= Matrix4x4::Rotation(r);
|
*this *= Matrix4x4::Rotation(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::rotateRelativePoint(const Point4D &s, const Point4D &v, double r) {
|
void Mesh::rotateRelativePoint(const Vec3D &s, const Vec3D &v, double r) {
|
||||||
Object::rotateRelativePoint(s, v, r);
|
Object::rotateRelativePoint(s, v, r);
|
||||||
*this *= Matrix4x4::Rotation(v, r);
|
*this *= Matrix4x4::Rotation(v, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::setColor(sf::Color c) {
|
void Mesh::setColor(const sf::Color& c) {
|
||||||
_color = c;
|
_color = c;
|
||||||
for (auto& t : _tris)
|
|
||||||
t = Triangle(t[0], t[1], t[2], _color);
|
// change color of all mesh triangles:
|
||||||
|
std::vector<Triangle> newTriangles;
|
||||||
|
for(auto &t : _tris) {
|
||||||
|
newTriangles.emplace_back(Triangle(t[0], t[1], t[2], c));
|
||||||
|
}
|
||||||
|
setTriangles(newTriangles);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Mesh>> Mesh::LoadObjects(const string &filename, const string &materials, const Point4D &scale) {
|
std::vector<std::shared_ptr<Mesh>> Mesh::LoadObjects(const string &filename, const string &materials, const Vec3D &scale) {
|
||||||
std::vector<std::shared_ptr<Mesh>> objects;
|
std::vector<std::shared_ptr<Mesh>> objects;
|
||||||
map<string, sf::Color> maters;
|
map<string, sf::Color> maters;
|
||||||
|
|
||||||
|
@ -170,26 +166,27 @@ std::vector<std::shared_ptr<Mesh>> Mesh::LoadObjects(const string &filename, con
|
||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf::Color color) {
|
Mesh Mesh::LineTo(const Vec3D& from, const Vec3D& to, double line_width, const sf::Color& color) {
|
||||||
|
|
||||||
Mesh line;
|
Mesh line;
|
||||||
|
|
||||||
Point4D v1 = (to - from).normalized();
|
Vec3D v1 = (to - from).normalized();
|
||||||
Point4D v2 = from.cross3D(from + Point4D{1, 0, 0}).normalized();
|
Vec3D v2 = from.cross(from + Vec3D{1, 0, 0}).normalized();
|
||||||
Point4D v3 = v1.cross3D(v2).normalized();
|
Vec3D v3 = v1.cross(v2).normalized();
|
||||||
|
|
||||||
// from plane
|
// from plane
|
||||||
Point4D p1 = from - v2 * line_width/2.0 - v3 * line_width/2.0;
|
Point4D p1 = (from - v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p2 = from - v2 * line_width/2.0 + v3 * line_width/2.0;
|
Point4D p2 = (from - v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p3 = from + v2 * line_width/2.0 + v3 * line_width/2.0;
|
Point4D p3 = (from + v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p4 = from + v2 * line_width/2.0 - v3 * line_width/2.0;
|
Point4D p4 = (from + v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
|
||||||
// to plane
|
// to plane
|
||||||
Point4D p5 = to - v2 * line_width/2.0 - v3 * line_width/2.0;
|
Point4D p5 = (to - v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p6 = to - v2 * line_width/2.0 + v3 * line_width/2.0;
|
Point4D p6 = (to - v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p7 = to + v2 * line_width/2.0 + v3 * line_width/2.0;
|
Point4D p7 = (to + v2 * line_width/2.0 + v3 * line_width/2.0).makePoint4D();
|
||||||
Point4D p8 = to + v2 * line_width/2.0 - v3 * line_width/2.0;
|
Point4D p8 = (to + v2 * line_width/2.0 - v3 * line_width/2.0).makePoint4D();
|
||||||
|
|
||||||
line._tris = {
|
|
||||||
|
line._tris = std::move(std::vector<Triangle>{
|
||||||
{ p2, p4, p1 },
|
{ p2, p4, p1 },
|
||||||
{ p2, p3, p4 },
|
{ p2, p3, p4 },
|
||||||
{ p1, p6, p2 },
|
{ p1, p6, p2 },
|
||||||
|
@ -202,14 +199,19 @@ Mesh Mesh::LineTo(const Point4D& from, const Point4D& to, double line_width, sf:
|
||||||
{ p4, p7, p8 },
|
{ p4, p7, p8 },
|
||||||
{ p1, p8, p5 },
|
{ p1, p8, p5 },
|
||||||
{ p1, p4, p8 }
|
{ p1, p4, p8 }
|
||||||
};
|
});
|
||||||
|
|
||||||
line.setColor(color);
|
line.setColor(color);
|
||||||
|
|
||||||
for(auto& triangle : line._tris)
|
|
||||||
triangle = Triangle(Point4D{triangle[0].x(), triangle[0].y(), triangle[0].z(), 1},
|
|
||||||
Point4D{triangle[1].x(), triangle[1].y(), triangle[1].z(), 1},
|
|
||||||
Point4D{triangle[2].x(), triangle[2].y(), triangle[2].z(), 1}, line.color());
|
|
||||||
|
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Mesh::Mesh(const Mesh &mesh) : _tris(mesh._tris), _color(mesh._color), _visible(mesh._visible) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::setTriangles(const vector<Triangle> &t) {
|
||||||
|
_tris.clear();
|
||||||
|
for (auto & tri : t) {
|
||||||
|
_tris.push_back(tri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,38 +19,38 @@ private:
|
||||||
Mesh& operator*=(const Matrix4x4& matrix4X4);
|
Mesh& operator*=(const Matrix4x4& matrix4X4);
|
||||||
public:
|
public:
|
||||||
Mesh() = default;
|
Mesh() = default;
|
||||||
|
Mesh& operator=(const Mesh& mesh) = delete;
|
||||||
Mesh(const Mesh& mesh);
|
Mesh(const Mesh& mesh);
|
||||||
|
|
||||||
explicit Mesh(const std::vector<Triangle>& tries);
|
explicit Mesh(const std::vector<Triangle>& tries);
|
||||||
Mesh& operator=(const Mesh& mesh);
|
explicit Mesh(const std::string& filename, const std::string &materials = "", const Vec3D& scale = Vec3D{1, 1, 1});
|
||||||
explicit Mesh(const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
|
|
||||||
|
|
||||||
Mesh& loadObj(const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
|
Mesh& loadObj(const std::string& filename, const std::string &materials = "", const Vec3D& scale = Vec3D{1, 1, 1});
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Triangle>const &triangles() const { return _tris; }
|
[[nodiscard]] std::vector<Triangle>const &triangles() const { return _tris; }
|
||||||
[[nodiscard]] std::vector<Triangle>& triangles() { return _tris; }
|
[[nodiscard]] std::vector<Triangle>& triangles() { return _tris; }
|
||||||
void setTriangles(const std::vector<Triangle>& t) { _tris = t; }
|
void setTriangles(const std::vector<Triangle>& t);
|
||||||
|
|
||||||
// Translate body
|
// Translate body
|
||||||
// Rotate body around XYZ axes
|
// Rotate body around XYZ axes
|
||||||
void rotate(const Point4D& r) override;
|
void rotate(const Vec3D& r) override;
|
||||||
// Rotate body around normalised vector 'v' by 'r' radians
|
// Rotate body around normalised vector 'v' by 'r' radians
|
||||||
void rotate(const Point4D& v, double r) override;
|
void rotate(const Vec3D& v, double r) override;
|
||||||
// Rotate body around XYZ by (r._x, r._y, r.z) radians relative val 'point4D'
|
// Rotate body around XYZ by (r._x, r._y, r.z) radians relative val 'point4D'
|
||||||
void rotateRelativePoint(const Point4D& point4D, const Point4D& r) override;
|
void rotateRelativePoint(const Vec3D& point, const Vec3D& r) override;
|
||||||
// Rotate body around normalised vector 'v' by 'r' radians relative val 'point4D'
|
// Rotate body around normalised vector 'v' by 'r' radians relative val 'point4D'
|
||||||
void rotateRelativePoint(const Point4D& point4D, const Point4D& v, double r) override;
|
void rotateRelativePoint(const Vec3D& point4D, const Vec3D& v, double r) override;
|
||||||
void scale(const Point4D& s) override;
|
void scale(const Vec3D& s) override;
|
||||||
|
|
||||||
[[nodiscard]] sf::Color color() const { return _color; }
|
[[nodiscard]] sf::Color color() const { return _color; }
|
||||||
void setColor(sf::Color c);
|
void setColor(const sf::Color& c);
|
||||||
|
|
||||||
void setVisible(bool visibility) { _visible = visibility; }
|
void setVisible(bool visibility) { _visible = visibility; }
|
||||||
[[nodiscard]] bool isVisible() const { return _visible; }
|
[[nodiscard]] bool isVisible() const { return _visible; }
|
||||||
|
|
||||||
Mesh static Obj(const std::string& filename);
|
Mesh static Obj(const std::string& filename);
|
||||||
std::vector<std::shared_ptr<Mesh>> static LoadObjects(const std::string& filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
|
std::vector<std::shared_ptr<Mesh>> static LoadObjects(const std::string& filename, const std::string &materials = "", const Vec3D& scale = Vec3D{1, 1, 1});
|
||||||
Mesh static LineTo(const Point4D& from, const Point4D& to, double line_width = 0.1, sf::Color color = {150, 150, 150, 255});
|
Mesh static LineTo(const Vec3D& from, const Vec3D& to, double line_width = 0.1, const sf::Color& color = {150, 150, 150, 255});
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //INC_3DZAVR_MESH_H
|
#endif //INC_3DZAVR_MESH_H
|
||||||
|
|
|
@ -5,18 +5,18 @@
|
||||||
#include "Mouse.h"
|
#include "Mouse.h"
|
||||||
#include "utils/Time.h"
|
#include "utils/Time.h"
|
||||||
|
|
||||||
Point4D Mouse::getMousePosition() const {
|
Vec2D Mouse::getMousePosition() const {
|
||||||
sf::Vector2<int> pos = sf::Mouse::getPosition(*_window);
|
sf::Vector2<int> pos = sf::Mouse::getPosition(*_window);
|
||||||
return Point4D(pos.x, pos.y, 0, 0);
|
return Vec2D(pos.x, pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Mouse::getMouseDisplacement() const {
|
Vec2D Mouse::getMouseDisplacement() const {
|
||||||
sf::Vector2<int> mousePos = sf::Mouse::getPosition(*_window);
|
sf::Vector2<int> mousePos = sf::Mouse::getPosition(*_window);
|
||||||
sf::Vector2<int> center = sf::Vector2<int>(_window->getSize().x/2, _window->getSize().y/2);
|
sf::Vector2<int> center = sf::Vector2<int>(_window->getSize().x/2, _window->getSize().y/2);
|
||||||
|
|
||||||
sf::Vector2<int> displacement = mousePos - center;
|
sf::Vector2<int> displacement = mousePos - center;
|
||||||
//setMouseInCenter();
|
//setMouseInCenter();
|
||||||
return Point4D(displacement.x, displacement.y, 0, 0);
|
return Vec2D(displacement.x, displacement.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mouse::setMouseInCenter() const {
|
void Mouse::setMouseInCenter() const {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
#include "utils/Point4D.h"
|
#include "Vec2D.h"
|
||||||
|
|
||||||
class Mouse {
|
class Mouse {
|
||||||
private:
|
private:
|
||||||
|
@ -22,8 +22,8 @@ public:
|
||||||
static bool isButtonPressed(sf::Mouse::Button button); // returns true if this _button is _pressed
|
static bool isButtonPressed(sf::Mouse::Button button); // returns true if this _button is _pressed
|
||||||
bool isButtonTapped(sf::Mouse::Button button); // returns true if this _button is tapped and 1/5 sec passed (_button bouncing problem solved)
|
bool isButtonTapped(sf::Mouse::Button button); // returns true if this _button is tapped and 1/5 sec passed (_button bouncing problem solved)
|
||||||
|
|
||||||
[[nodiscard]] Point4D getMousePosition() const;
|
[[nodiscard]] Vec2D getMousePosition() const;
|
||||||
[[nodiscard]] Point4D getMouseDisplacement() const;
|
[[nodiscard]] Vec2D getMouseDisplacement() const;
|
||||||
void setMouseInCenter() const;
|
void setMouseInCenter() const;
|
||||||
void setMouseCursorVisible(bool visible);
|
void setMouseCursorVisible(bool visible);
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,114 +3,121 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
#include "utils/Matrix4x4.h"
|
#include "Matrix4x4.h"
|
||||||
#include "utils/Log.h"
|
#include "utils/Log.h"
|
||||||
|
|
||||||
void Object::translate(const Point4D &dv) {
|
void Object::translate(const Vec3D &dv) {
|
||||||
_position = _position + dv;
|
_position = std::make_unique<Vec3D>(*_position + dv);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->translate(dv);
|
attached.second->translate(dv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::scale(const Point4D &s) {
|
void Object::scale(const Vec3D &s) {
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->scale(s);
|
attached.second->scale(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotate(const Point4D &r) {
|
void Object::rotate(const Vec3D &r) {
|
||||||
_angle = _angle + r;
|
_angle = std::make_unique<Vec3D>(*_angle + r);
|
||||||
|
|
||||||
Matrix4x4 rotationMatrix = Matrix4x4::RotationZ(r.z())*Matrix4x4::RotationY(r.y())*Matrix4x4::RotationX(r.z());
|
Matrix4x4 rotationMatrix = Matrix4x4::RotationZ(r.z())*Matrix4x4::RotationY(r.y())*Matrix4x4::RotationX(r.z());
|
||||||
|
|
||||||
_left = rotationMatrix * _left;
|
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
|
||||||
_up = rotationMatrix * _up;
|
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
|
||||||
_lookAt = rotationMatrix * _lookAt;
|
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(position(), r);
|
attached.second->rotateRelativePoint(position(), r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotate(const Point4D &v, double rv) {
|
void Object::rotate(const Vec3D &v, double rv) {
|
||||||
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, rv);
|
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, rv);
|
||||||
_left = rotationMatrix * _left;
|
|
||||||
_up = rotationMatrix * _up;
|
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
|
||||||
_lookAt = rotationMatrix * _lookAt;
|
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
|
||||||
|
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(position(), v, rv);
|
attached.second->rotateRelativePoint(position(), v, rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateRelativePoint(const Point4D &s, const Point4D &r) {
|
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &r) {
|
||||||
_angle = _angle + r;
|
_angle = std::make_unique<Vec3D>(*_angle + r);
|
||||||
|
|
||||||
// Translate XYZ by vector r1
|
// Translate XYZ by vector r1
|
||||||
Point4D r1 = _position - s;
|
Vec3D r1(*_position - s);
|
||||||
|
|
||||||
// In translated coordinate system we rotate body and position
|
// In translated coordinate system we rotate body and position
|
||||||
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(r);
|
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(r);
|
||||||
Point4D r2 = rotationMatrix*r1;
|
Vec3D r2(rotationMatrix*r1);
|
||||||
|
|
||||||
_left = rotationMatrix * _left;
|
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
|
||||||
_up = rotationMatrix * _up;
|
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
|
||||||
_lookAt = rotationMatrix * _lookAt;
|
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
|
||||||
|
|
||||||
// After rotation we translate XYZ by vector -r2 and recalculate position
|
// After rotation we translate XYZ by vector -r2 and recalculate position
|
||||||
_position = s + r2;
|
_position = std::make_unique<Vec3D>(s + r2);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(s, r);
|
attached.second->rotateRelativePoint(s, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateRelativePoint(const Point4D &s, const Point4D &v, double r) {
|
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &v, double r) {
|
||||||
// Translate XYZ by vector r1
|
// Translate XYZ by vector r1
|
||||||
Point4D r1 = _position - s;
|
Vec3D r1(*_position - s);
|
||||||
// In translated coordinate system we rotate body and position
|
// In translated coordinate system we rotate body and position
|
||||||
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, r);
|
Matrix4x4 rotationMatrix = Matrix4x4::Rotation(v, r);
|
||||||
Point4D r2 = rotationMatrix*r1;
|
Vec3D r2 = rotationMatrix*r1;
|
||||||
|
|
||||||
_left = rotationMatrix * _left;
|
_left = std::make_unique<Vec3D>(rotationMatrix * *_left);
|
||||||
_up = rotationMatrix * _up;
|
_up = std::make_unique<Vec3D>(rotationMatrix * *_up);
|
||||||
_lookAt = rotationMatrix * _lookAt;
|
_lookAt = std::make_unique<Vec3D>(rotationMatrix * *_lookAt);
|
||||||
|
|
||||||
// After rotation we translate XYZ by vector -r2 and recalculate position
|
// After rotation we translate XYZ by vector -r2 and recalculate position
|
||||||
_position = s + r2;
|
_position = std::make_unique<Vec3D>(s + r2);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(s, v, r);
|
attached.second->rotateRelativePoint(s, v, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateLeft(double rl) {
|
void Object::rotateLeft(double rl) {
|
||||||
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x() + rl, _angleLeftUpLookAt.y(), _angleLeftUpLookAt.z()};
|
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x() + rl,
|
||||||
|
_angleLeftUpLookAt->y(),
|
||||||
|
_angleLeftUpLookAt->z()});
|
||||||
|
|
||||||
rotate(_left, rl);
|
rotate(*_left, rl);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(position(), _left, rl);
|
attached.second->rotateRelativePoint(position(), *_left, rl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateUp(double ru) {
|
void Object::rotateUp(double ru) {
|
||||||
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x(), _angleLeftUpLookAt.y() + ru, _angleLeftUpLookAt.z()};
|
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x(),
|
||||||
rotate(_up, ru);
|
_angleLeftUpLookAt->y() + ru,
|
||||||
|
_angleLeftUpLookAt->z()});
|
||||||
|
rotate(*_up, ru);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(position(), _up, ru);
|
attached.second->rotateRelativePoint(position(), *_up, ru);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateLookAt(double rlAt) {
|
void Object::rotateLookAt(double rlAt) {
|
||||||
_angleLeftUpLookAt = Point4D{_angleLeftUpLookAt.x(), _angleLeftUpLookAt.y(), _angleLeftUpLookAt.z() + rlAt};
|
_angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{_angleLeftUpLookAt->x(),
|
||||||
rotate(_lookAt, rlAt);
|
_angleLeftUpLookAt->y(),
|
||||||
|
_angleLeftUpLookAt->z() + rlAt});
|
||||||
|
rotate(*_lookAt, rlAt);
|
||||||
|
|
||||||
for(auto attached : _attachedObjects)
|
for(auto attached : _attachedObjects)
|
||||||
attached.second->rotateRelativePoint(position(), _lookAt, rlAt);
|
attached.second->rotateRelativePoint(position(), *_lookAt, rlAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::translateToPoint(const Point4D &point) {
|
void Object::translateToPoint(const Vec3D &point) {
|
||||||
translate(point - _position);
|
translate(point - *_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::rotateToAngle(const Point4D &v) {
|
void Object::rotateToAngle(const Vec3D &v) {
|
||||||
rotate(v - _angle);
|
rotate(v - *_angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Object> Object::attached(const std::string &name) {
|
std::shared_ptr<Object> Object::attached(const std::string &name) {
|
||||||
|
@ -120,7 +127,11 @@ std::shared_ptr<Object> Object::attached(const std::string &name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::attach(std::shared_ptr<Object> object, const std::string &name) {
|
void Object::attach(std::shared_ptr<Object> object, const std::string &name) {
|
||||||
|
// TODO: solve problem with possible infinite recursive call chains
|
||||||
|
if(this != object.get())
|
||||||
_attachedObjects.emplace(name, object);
|
_attachedObjects.emplace(name, object);
|
||||||
|
else
|
||||||
|
throw std::invalid_argument{"Object::attach: You cannot attach object to itself"};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Object::unattach(const std::string &name) {
|
void Object::unattach(const std::string &name) {
|
||||||
|
|
|
@ -6,40 +6,40 @@
|
||||||
#define ENGINE_OBJECT_H
|
#define ENGINE_OBJECT_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "utils/Point4D.h"
|
#include "Vec3D.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Object {
|
class Object {
|
||||||
protected:
|
protected:
|
||||||
Point4D _left = Point4D{1, 0, 0, 0}; // internal X
|
std::unique_ptr<Vec3D> _left = std::make_unique<Vec3D>(Vec3D{1, 0, 0}); // internal X
|
||||||
Point4D _up = Point4D{0, 1, 0, 0}; // internal Y
|
std::unique_ptr<Vec3D> _up = std::make_unique<Vec3D>(Vec3D{0, 1, 0}); // internal Y
|
||||||
Point4D _lookAt = Point4D{0, 0, 1, 0}; // internal Z
|
std::unique_ptr<Vec3D> _lookAt = std::make_unique<Vec3D>(Vec3D{0, 0, 1}); // internal Z
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<Object>> _attachedObjects;
|
std::map<std::string, std::shared_ptr<Object>> _attachedObjects;
|
||||||
|
|
||||||
Point4D _position;
|
std::unique_ptr<Vec3D> _position = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
|
||||||
Point4D _angle;
|
std::unique_ptr<Vec3D> _angle = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
|
||||||
Point4D _angleLeftUpLookAt;
|
std::unique_ptr<Vec3D> _angleLeftUpLookAt = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
|
||||||
public:
|
public:
|
||||||
Object() = default;
|
Object() = default;
|
||||||
|
|
||||||
virtual void translate(const Point4D& dv);
|
virtual void translate(const Vec3D& dv);
|
||||||
virtual void translateToPoint(const Point4D& point);
|
virtual void translateToPoint(const Vec3D& point);
|
||||||
virtual void scale(const Point4D& s);
|
virtual void scale(const Vec3D& s);
|
||||||
virtual void rotate(const Point4D& r);
|
virtual void rotate(const Vec3D& r);
|
||||||
virtual void rotate(const Point4D& v, double rv);
|
virtual void rotate(const Vec3D& v, double rv);
|
||||||
virtual void rotateToAngle(const Point4D& v);
|
virtual void rotateToAngle(const Vec3D& v);
|
||||||
virtual void rotateRelativePoint(const Point4D& s, const Point4D& r);
|
virtual void rotateRelativePoint(const Vec3D& s, const Vec3D& r);
|
||||||
virtual void rotateRelativePoint(const Point4D& s, const Point4D& v, double r);
|
virtual void rotateRelativePoint(const Vec3D& s, const Vec3D& v, double r);
|
||||||
|
|
||||||
[[nodiscard]] Point4D position() const { return _position; }
|
[[nodiscard]] Vec3D position() const { return *_position; }
|
||||||
[[nodiscard]] Point4D angle() const { return _angle; }
|
[[nodiscard]] Vec3D angle() const { return *_angle; }
|
||||||
[[nodiscard]] Point4D angleLeftUpLookAt() const { return _angleLeftUpLookAt; }
|
[[nodiscard]] Vec3D angleLeftUpLookAt() const { return *_angleLeftUpLookAt; }
|
||||||
|
|
||||||
[[nodiscard]] Point4D left() const { return _left; }
|
[[nodiscard]] Vec3D left() const { return *_left; }
|
||||||
[[nodiscard]] Point4D up() const { return _up; }
|
[[nodiscard]] Vec3D up() const { return *_up; }
|
||||||
[[nodiscard]] Point4D lookAt() const { return _lookAt; }
|
[[nodiscard]] Vec3D lookAt() const { return *_lookAt; }
|
||||||
|
|
||||||
void rotateLeft(double rl);
|
void rotateLeft(double rl);
|
||||||
void rotateUp(double ru);
|
void rotateUp(double ru);
|
||||||
|
|
|
@ -4,75 +4,71 @@
|
||||||
|
|
||||||
#include "Plane.h"
|
#include "Plane.h"
|
||||||
|
|
||||||
Plane::Plane(const Triangle& tri) {
|
Plane::Plane(const Triangle& tri) : _triangle(tri), _n(tri.norm()), _p(tri[0]) {
|
||||||
_triangle = tri;
|
|
||||||
_n = tri.norm();
|
|
||||||
_p = tri[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Plane::Plane(const Point4D &N, const Point4D &P) {
|
Plane::Plane(const Vec3D &N, const Vec3D &P) : _n(N.normalized()), _p(P) {
|
||||||
_n = N.normalized();
|
|
||||||
_p = P;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Plane::Plane(const Plane &plane) {
|
double Plane::distance(const Vec3D &point) const {
|
||||||
_triangle = plane._triangle;
|
return point.dot(_n) - _p.dot(_n);
|
||||||
_n = plane._n;
|
|
||||||
_p = plane._p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double Plane::distance(const Point4D &point4D) const {
|
std::pair<Vec3D, double> Plane::intersection(const Vec3D &start, const Vec3D &end) const {
|
||||||
return point4D.dot(_n) - _p.dot(_n);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<Point4D, double> Plane::intersection(const Point4D &start, const Point4D &end) const {
|
|
||||||
double s_dot_n = start.dot(_n);
|
double s_dot_n = start.dot(_n);
|
||||||
double k = (s_dot_n - _p.dot(_n)) / (s_dot_n - end.dot(_n));
|
double k = (s_dot_n - _p.dot(_n)) / (s_dot_n - end.dot(_n));
|
||||||
Point4D res = start + (end - start)*k;
|
Vec3D res = start + (end - start)*k;
|
||||||
return std::make_pair(res, k);
|
return std::make_pair(res, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Plane::clip(Triangle &tri, Triangle &additional_tri) const {
|
std::vector<Triangle> Plane::clip(const Triangle &tri) const {
|
||||||
|
|
||||||
Point4D insidePoints[3]; int inside = 0;
|
std::vector<Triangle> result;
|
||||||
Point4D outsidePoints[3]; int outside = 0;
|
|
||||||
|
|
||||||
double distances[3] = {distance(tri[0]), distance(tri[1]), distance(tri[2])};
|
std::vector<Vec3D> insidePoints;
|
||||||
|
std::vector<Vec3D> outsidePoints;
|
||||||
|
|
||||||
|
double distances[3] = {distance(Vec3D(tri[0])),
|
||||||
|
distance(Vec3D(tri[1])),
|
||||||
|
distance(Vec3D(tri[2]))};
|
||||||
|
|
||||||
for(int i = 0; i < 3; i++) {
|
for(int i = 0; i < 3; i++) {
|
||||||
if (distances[i] >= 0) {
|
if (distances[i] >= 0) {
|
||||||
insidePoints[inside++] = tri[i];
|
insidePoints.emplace_back(tri[i]);
|
||||||
} else {
|
} else {
|
||||||
outsidePoints[outside++] = tri[i];
|
outsidePoints.emplace_back(tri[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inside == 0) {
|
if(insidePoints.size() == 1) {
|
||||||
return 0;
|
std::pair<Vec3D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
|
||||||
|
std::pair<Vec3D, double> intersect2 = intersection(insidePoints[0], outsidePoints[1]);
|
||||||
|
|
||||||
|
result.emplace_back(insidePoints[0].makePoint4D(),
|
||||||
|
intersect1.first.makePoint4D(),
|
||||||
|
intersect2.first.makePoint4D(),
|
||||||
|
tri.color());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inside == 1) {
|
if(insidePoints.size() == 2) {
|
||||||
std::pair<Point4D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
|
std::pair<Vec3D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
|
||||||
std::pair<Point4D, double> intersect2 = intersection(insidePoints[0], outsidePoints[1]);
|
std::pair<Vec3D, double> intersect2 = intersection(insidePoints[1], outsidePoints[0]);
|
||||||
|
|
||||||
tri = Triangle(insidePoints[0], intersect1.first, intersect2.first, tri.color());
|
result.emplace_back(insidePoints[0].makePoint4D(),
|
||||||
|
intersect1.first.makePoint4D(),
|
||||||
return 1;
|
insidePoints[1].makePoint4D(),
|
||||||
|
tri.color());
|
||||||
|
result.emplace_back(intersect1.first.makePoint4D(),
|
||||||
|
intersect2.first.makePoint4D(),
|
||||||
|
insidePoints[1].makePoint4D(),
|
||||||
|
tri.color());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inside == 2) {
|
if(insidePoints.size() == 3) {
|
||||||
std::pair<Point4D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
|
result.emplace_back(tri);
|
||||||
std::pair<Point4D, double> intersect2 = intersection(insidePoints[1], outsidePoints[0]);
|
|
||||||
|
|
||||||
tri = Triangle(insidePoints[0], intersect1.first, insidePoints[1], tri.color());
|
|
||||||
additional_tri = Triangle(intersect1.first, intersect2.first, insidePoints[1], tri.color());
|
|
||||||
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inside == 3) {
|
return result;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef ENGINE_PLANE_H
|
#ifndef ENGINE_PLANE_H
|
||||||
#define ENGINE_PLANE_H
|
#define ENGINE_PLANE_H
|
||||||
|
|
||||||
#include "utils/Point4D.h"
|
#include "Point4D.h"
|
||||||
#include "Triangle.h"
|
#include "Triangle.h"
|
||||||
|
|
||||||
class Plane {
|
class Plane {
|
||||||
|
@ -13,22 +13,22 @@ private:
|
||||||
// You can define plane by defining the points in 3D space
|
// You can define plane by defining the points in 3D space
|
||||||
Triangle _triangle;
|
Triangle _triangle;
|
||||||
// Or by defining normal vector and one val laying on the plane
|
// Or by defining normal vector and one val laying on the plane
|
||||||
Point4D _n = Point4D{0, 0, 1, 0};
|
Vec3D _n = Vec3D{0, 0, 1};
|
||||||
Point4D _p{};
|
Vec3D _p{};
|
||||||
public:
|
public:
|
||||||
// A plain with normal vector '_n' and val '_p' lays on the plane
|
// A plain with normal vector '_n' and val '_p' lays on the plane
|
||||||
Plane() = default;
|
Plane() = default;
|
||||||
Plane(const Point4D& N, const Point4D& P);
|
Plane(const Vec3D& N, const Vec3D& P);
|
||||||
Plane(const Plane& plane);
|
Plane(const Plane& plane) = default;
|
||||||
explicit Plane(const Triangle& tri);
|
explicit Plane(const Triangle& tri);
|
||||||
|
|
||||||
[[nodiscard]] double distance(const Point4D& point4D) const;
|
[[nodiscard]] double distance(const Vec3D& point4D) const;
|
||||||
// Point4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
|
// Point4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
|
||||||
[[nodiscard]] std::pair<Point4D, double> intersection(const Point4D& start, const Point4D& end) const;
|
[[nodiscard]] std::pair<Vec3D, double> intersection(const Vec3D& start, const Vec3D& end) const;
|
||||||
int clip(Triangle& tri, Triangle& additional_tri) const;
|
[[nodiscard]] std::vector<Triangle> clip(const Triangle& tri) const;
|
||||||
|
|
||||||
[[nodiscard]] Point4D N() const { return _n; }
|
[[nodiscard]] Vec3D N() const { return _n; }
|
||||||
[[nodiscard]] Point4D P() const { return _p; }
|
[[nodiscard]] Vec3D P() const { return _p; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "Point4D.h"
|
#include "Point4D.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
Point4D::Point4D (double x, double y, double z, double w) {
|
Point4D::Point4D (double x, double y, double z, double w) {
|
||||||
_arr_point[0] = x;
|
_arr_point[0] = x;
|
||||||
|
@ -19,60 +20,51 @@ Point4D::Point4D(const Point4D &point4D) {
|
||||||
_arr_point[3] = point4D.w();
|
_arr_point[3] = point4D.w();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double Point4D::operator[] (int i) const {
|
|
||||||
return _arr_point[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Point4D Point4D::operator-() const {
|
[[nodiscard]] Point4D Point4D::operator-() const {
|
||||||
return Point4D(-x(), -y(), -z(), -w());
|
return Point4D(-x(), -y(), -z(), -w());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Point4D::operator==(const Point4D& point4D) const
|
bool Point4D::operator==(const Point4D& point4D) const {
|
||||||
{
|
return (*this - point4D).sqrAbs() < Consts::EPS;
|
||||||
return this == &point4D || (*this - point4D).sqrAbs() < 0.0000000001;
|
|
||||||
}
|
}
|
||||||
bool Point4D::operator!=(const Point4D& point4D) const
|
|
||||||
{
|
bool Point4D::operator!=(const Point4D& point4D) const {
|
||||||
return this != &point4D && (*this - point4D).sqrAbs() > 0.0000000001;
|
return !(*this == point4D);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Operations with Point4D
|
// Operations with Point4D
|
||||||
Point4D Point4D::operator+(const Point4D& point4D) const {
|
Point4D Point4D::operator+(const Point4D& point4D) const {
|
||||||
return Point4D(x()+point4D.x(), y()+point4D.y(), z()+point4D.z(), w()+point4D.w());
|
return Point4D(x()+point4D.x(), y()+point4D.y(), z()+point4D.z(), w()+point4D.w());
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Point4D::operator-(const Point4D& point4D) const {
|
Point4D Point4D::operator-(const Point4D& point4D) const {
|
||||||
return Point4D(*this) + -point4D;
|
return Point4D(*this) + -point4D;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Point4D::dot(const Point4D& point4D) const
|
|
||||||
{
|
|
||||||
return point4D.x() * x() + point4D.y() * y() + point4D.z() * z();
|
|
||||||
}
|
|
||||||
[[nodiscard]] Point4D Point4D::cross3D(const Point4D& point4D) const {
|
|
||||||
return Point4D {y() * point4D.z() - point4D.y() * z(),
|
|
||||||
z() * point4D.x() - point4D.z() * x(),
|
|
||||||
x() * point4D.y() - point4D.x() * y()};
|
|
||||||
}
|
|
||||||
|
|
||||||
Point4D Point4D::operator*(double number) const {
|
Point4D Point4D::operator*(double number) const {
|
||||||
return Point4D(x()*number, y()*number, z()*number, w()*number);
|
return Point4D(x()*number, y()*number, z()*number, w()*number);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Point4D::operator/(double number) const {
|
Point4D Point4D::operator/(double number) const {
|
||||||
if(number != 0)
|
if(std::abs(number) > Consts::EPS)
|
||||||
return Point4D(*this)*(1.0/number);
|
return Point4D(*this)*(1.0/number);
|
||||||
else
|
else
|
||||||
return Point4D();
|
throw std::domain_error{"Point4D::operator/(double number): division by zero"};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other useful methods
|
// Other useful methods
|
||||||
double Point4D::sqrAbs() const
|
double Point4D::sqrAbs() const {
|
||||||
{
|
|
||||||
return x()*x() + y()*y() + z()*z();
|
return x()*x() + y()*y() + z()*z();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Point4D::abs() const {
|
double Point4D::abs() const {
|
||||||
return sqrt(sqrAbs());
|
return sqrt(sqrAbs());
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Point4D::normalized() const {
|
Point4D Point4D::normalized() const {
|
||||||
|
double vecAbs = abs();
|
||||||
|
if(vecAbs > Consts::EPS)
|
||||||
return Point4D(*this)/abs();
|
return Point4D(*this)/abs();
|
||||||
|
else
|
||||||
|
return Point4D(0);
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#define ENGINE_POINT4D_H
|
#define ENGINE_POINT4D_H
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include "Consts.h"
|
||||||
|
|
||||||
class Point4D {
|
class Point4D {
|
||||||
private:
|
private:
|
||||||
|
@ -14,16 +15,15 @@ private:
|
||||||
public:
|
public:
|
||||||
Point4D () = default;
|
Point4D () = default;
|
||||||
Point4D (const Point4D& point4D);
|
Point4D (const Point4D& point4D);
|
||||||
Point4D& operator=(const Point4D& point4D) { _arr_point = point4D._arr_point; return *this; };
|
|
||||||
explicit Point4D (double x, double y = 0.0, double z = 0.0, double w = 0.0);
|
explicit Point4D (double x, double y = 0.0, double z = 0.0, double w = 0.0);
|
||||||
|
Point4D& operator=(const Point4D& point4D) = delete;
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] double x() const { return _arr_point[0]; }
|
[[nodiscard]] double x() const { return _arr_point[0]; }
|
||||||
[[nodiscard]] double y() const { return _arr_point[1]; }
|
[[nodiscard]] double y() const { return _arr_point[1]; }
|
||||||
[[nodiscard]] double z() const { return _arr_point[2]; }
|
[[nodiscard]] double z() const { return _arr_point[2]; }
|
||||||
[[nodiscard]] double w() const { return _arr_point[3]; }
|
[[nodiscard]] double w() const { return _arr_point[3]; }
|
||||||
|
|
||||||
[[nodiscard]] double operator[] (int i) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Point4D operator-() const;
|
[[nodiscard]] Point4D operator-() const;
|
||||||
|
|
||||||
// Boolean operations
|
// Boolean operations
|
||||||
|
@ -34,9 +34,6 @@ public:
|
||||||
[[nodiscard]] Point4D operator+(const Point4D& point4D) const;
|
[[nodiscard]] Point4D operator+(const Point4D& point4D) const;
|
||||||
[[nodiscard]] Point4D operator-(const Point4D& point4D) const;
|
[[nodiscard]] Point4D operator-(const Point4D& point4D) const;
|
||||||
|
|
||||||
[[nodiscard]] double dot(const Point4D& point4D) const; // Returns dot product
|
|
||||||
[[nodiscard]] Point4D cross3D(const Point4D& point4D) const; // Returns cross product
|
|
||||||
|
|
||||||
// Operations with numbers
|
// Operations with numbers
|
||||||
[[nodiscard]] Point4D operator*(double number) const;
|
[[nodiscard]] Point4D operator*(double number) const;
|
||||||
[[nodiscard]] Point4D operator/(double number) const;
|
[[nodiscard]] Point4D operator/(double number) const;
|
|
@ -78,7 +78,7 @@ void Screen::debugText(const std::string& text) {
|
||||||
_window->draw(t);
|
_window->draw(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::drawTetragon(const Point4D &p1, const Point4D &p2, const Point4D &p3, const Point4D &p4, sf::Color color) {
|
void Screen::drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, const Vec2D &p4, sf::Color color) {
|
||||||
sf::ConvexShape polygon;
|
sf::ConvexShape polygon;
|
||||||
polygon.setPointCount(4);
|
polygon.setPointCount(4);
|
||||||
polygon.setPoint(0, sf::Vector2f((float)p1.x(), (float)p1.y()));
|
polygon.setPoint(0, sf::Vector2f((float)p1.x(), (float)p1.y()));
|
||||||
|
@ -89,7 +89,7 @@ void Screen::drawTetragon(const Point4D &p1, const Point4D &p2, const Point4D &p
|
||||||
_window->draw(polygon);
|
_window->draw(polygon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::drawText(const std::string& string, const Point4D &position, int size, sf::Color color) {
|
void Screen::drawText(const std::string& string, const Vec2D &position, int size, sf::Color color) {
|
||||||
sf::Text text;
|
sf::Text text;
|
||||||
|
|
||||||
text.setFont(*ResourceManager::loadFont("engine/fonts/Roboto-Medium.ttf"));
|
text.setFont(*ResourceManager::loadFont("engine/fonts/Roboto-Medium.ttf"));
|
||||||
|
|
|
@ -33,8 +33,8 @@ public:
|
||||||
bool hasFocus() const { return _window->hasFocus(); }
|
bool hasFocus() const { return _window->hasFocus(); }
|
||||||
|
|
||||||
void drawTriangle(const Triangle& triangle);
|
void drawTriangle(const Triangle& triangle);
|
||||||
void drawTetragon(const Point4D& p1, const Point4D& p2, const Point4D& p3, const Point4D& p4, sf::Color color);
|
void drawTetragon(const Vec2D& p1, const Vec2D& p2, const Vec2D& p3, const Vec2D& p4, sf::Color color);
|
||||||
void drawText(const std::string& string, const Point4D& position, int size, sf::Color color);
|
void drawText(const std::string& string, const Vec2D& position, int size, sf::Color color);
|
||||||
void drawText(const sf::Text& text);
|
void drawText(const sf::Text& text);
|
||||||
void drawSprite(const sf::Sprite& sprite);
|
void drawSprite(const sf::Sprite& sprite);
|
||||||
|
|
||||||
|
|
|
@ -5,53 +5,47 @@
|
||||||
#include "Triangle.h"
|
#include "Triangle.h"
|
||||||
|
|
||||||
Triangle::Triangle () {
|
Triangle::Triangle () {
|
||||||
_p[0] = Point4D{0, 0, 0, 1};
|
_points.emplace_back(Point4D(0, 0, 0, 1));
|
||||||
_p[1] = Point4D{0, 0, 0, 1};
|
_points.emplace_back(Point4D(0, 0, 0, 1));
|
||||||
_p[2] = Point4D{0, 0, 0, 1};
|
_points.emplace_back(Point4D(0, 0, 0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Triangle::Triangle(const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color) {
|
Triangle::Triangle(const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color) : _color(color) {
|
||||||
_p[0] = p1;
|
_points.emplace_back(Point4D(p1));
|
||||||
_p[1] = p2;
|
_points.emplace_back(Point4D(p2));
|
||||||
_p[2] = p3;
|
_points.emplace_back(Point4D(p3));
|
||||||
_color = color;
|
}
|
||||||
|
|
||||||
|
Triangle::Triangle(const Triangle &triangle) : _points(triangle._points), _color(triangle._color) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Triangle Triangle::operator*(const Matrix4x4 &matrix4X4) const {
|
Triangle Triangle::operator*(const Matrix4x4 &matrix4X4) const {
|
||||||
Triangle res(*this);
|
return Triangle(matrix4X4 * _points[0], matrix4X4 * _points[1], matrix4X4 * _points[2], _color);
|
||||||
|
|
||||||
res._p[0] = matrix4X4 * _p[0];
|
|
||||||
res._p[1] = matrix4X4 * _p[1];
|
|
||||||
res._p[2] = matrix4X4 * _p[2];
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Triangle::norm() const {
|
Vec3D Triangle::norm() const {
|
||||||
|
|
||||||
Point4D v1 = _p[1] - _p[0];
|
Vec3D v1 = Vec3D(_points[1] - _points[0]);
|
||||||
Point4D v2 = _p[2] - _p[0];
|
Vec3D v2 = Vec3D(_points[2] - _points[0]);
|
||||||
|
Vec3D crossProduct = v1.cross(v2);
|
||||||
|
|
||||||
return v1.cross3D(v2).normalized();
|
if(crossProduct.sqrAbs() > Consts::EPS)
|
||||||
|
return crossProduct.normalized();
|
||||||
|
else
|
||||||
|
return Vec3D(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D Triangle::operator[](int i) const {
|
Point4D Triangle::operator[](int i) const {
|
||||||
return _p[i];
|
return _points[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
Triangle::Triangle(const Triangle &triangle) {
|
bool Triangle::isPointInside(const Vec3D &point) const {
|
||||||
_color = triangle._color;
|
Vec3D triangleNorm = norm();
|
||||||
_p[0] = triangle[0];
|
|
||||||
_p[1] = triangle[1];
|
|
||||||
_p[2] = triangle[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Triangle::isPointInside(const Point4D &point) const {
|
double dot1 = (point - Vec3D(_points[0])).cross(Vec3D(_points[1] - _points[0])).dot(triangleNorm);
|
||||||
Point4D triangleNorm = norm();
|
double dot2 = (point - Vec3D(_points[1])).cross(Vec3D(_points[2] - _points[1])).dot(triangleNorm);
|
||||||
|
double dot3 = (point - Vec3D(_points[2])).cross(Vec3D(_points[0] - _points[2])).dot(triangleNorm);
|
||||||
double dot1 = (point - _p[0]).cross3D(_p[1] - _p[0]).dot(triangleNorm);
|
|
||||||
double dot2 = (point - _p[1]).cross3D(_p[2] - _p[1]).dot(triangleNorm);
|
|
||||||
double dot3 = (point - _p[2]).cross3D(_p[0] - _p[2]).dot(triangleNorm);
|
|
||||||
|
|
||||||
if((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0))
|
if((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0))
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -5,30 +5,32 @@
|
||||||
#ifndef ENGINE_TRIANGLE_H
|
#ifndef ENGINE_TRIANGLE_H
|
||||||
#define ENGINE_TRIANGLE_H
|
#define ENGINE_TRIANGLE_H
|
||||||
|
|
||||||
#include "utils/Point4D.h"
|
#include "Point4D.h"
|
||||||
#include "utils/Matrix4x4.h"
|
#include "Vec3D.h"
|
||||||
|
#include "Matrix4x4.h"
|
||||||
#include <SFML/Graphics.hpp>
|
#include <SFML/Graphics.hpp>
|
||||||
|
|
||||||
class Triangle {
|
class Triangle {
|
||||||
private:
|
private:
|
||||||
sf::Color _color;
|
sf::Color _color;
|
||||||
Point4D _p[3];
|
std::vector<Point4D> _points;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Triangle ();
|
Triangle ();
|
||||||
Triangle (const Triangle& triangle);
|
Triangle (const Triangle& triangle);
|
||||||
Triangle (const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color = {0, 0, 0});
|
Triangle (const Point4D& p1, const Point4D& p2, const Point4D& p3, sf::Color color = {0, 0, 0});
|
||||||
|
Triangle& operator=(const Triangle&) = delete;
|
||||||
|
|
||||||
[[nodiscard]] Point4D operator[] (int i) const;
|
[[nodiscard]] Point4D operator[] (int i) const;
|
||||||
[[nodiscard]] Point4D norm() const;
|
[[nodiscard]] Vec3D norm() const;
|
||||||
|
|
||||||
// Operations with Matrix4x4
|
// Operations with Matrix4x4
|
||||||
[[nodiscard]] Triangle operator*(const Matrix4x4& matrix4X4) const;
|
[[nodiscard]] Triangle operator*(const Matrix4x4& matrix4X4) const;
|
||||||
|
|
||||||
[[nodiscard]] bool isPointInside(const Point4D& point) const;
|
[[nodiscard]] bool isPointInside(const Vec3D& point) const;
|
||||||
|
|
||||||
[[nodiscard]] sf::Color color() const { return _color; }
|
[[nodiscard]] sf::Color color() const { return _color; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
//
|
||||||
|
// Created by Иван Ильин on 10.10.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include "Vec2D.h"
|
||||||
|
|
||||||
|
Vec2D::Vec2D(const Vec2D &vec) {
|
||||||
|
_arr_point[0] = vec.x();
|
||||||
|
_arr_point[1] = vec.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D::Vec2D (double x, double y) {
|
||||||
|
_arr_point[0] = x;
|
||||||
|
_arr_point[1] = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D::Vec2D(const Point4D &point4D) {
|
||||||
|
_arr_point[0] = point4D.x();
|
||||||
|
_arr_point[1] = point4D.y();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D Vec2D::operator-() const {
|
||||||
|
return Vec2D(-x(), -y());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vec2D::operator==(const Vec2D& vec) const {
|
||||||
|
return (*this - vec).sqrAbs() < Consts::EPS;
|
||||||
|
}
|
||||||
|
bool Vec2D::operator!=(const Vec2D& vec) const {
|
||||||
|
return !(*this == vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D Vec2D::operator+(const Vec2D& vec) const {
|
||||||
|
return Vec2D(x()+vec.x(), y()+vec.y());
|
||||||
|
}
|
||||||
|
Vec2D Vec2D::operator-(const Vec2D& vec) const {
|
||||||
|
return Vec2D(*this) + -vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D Vec2D::operator*(double number) const {
|
||||||
|
return Vec2D(x()*number, y()*number);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D Vec2D::operator/(double number) const {
|
||||||
|
if(std::abs(number) > Consts::EPS)
|
||||||
|
return Vec2D(*this)*(1.0/number);
|
||||||
|
else
|
||||||
|
throw std::domain_error{"Vec2D::operator/(double number): division by zero"};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other useful methods
|
||||||
|
double Vec2D::sqrAbs() const {
|
||||||
|
return x()*x() + y()*y();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Vec2D::abs() const {
|
||||||
|
return sqrt(sqrAbs());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2D Vec2D::normalized() const {
|
||||||
|
double vecAbs = abs();
|
||||||
|
if(vecAbs > Consts::EPS)
|
||||||
|
return Vec2D(*this)/abs();
|
||||||
|
else
|
||||||
|
return Vec2D(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Vec2D::dot(const Vec2D& vec) const {
|
||||||
|
return vec.x() * x() + vec.y() * y();
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
//
|
||||||
|
// Created by Иван Ильин on 10.10.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHOOTER_VEC2D_H
|
||||||
|
#define SHOOTER_VEC2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "Point4D.h"
|
||||||
|
|
||||||
|
class Vec2D {
|
||||||
|
private:
|
||||||
|
std::array<double, 2> _arr_point{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vec2D () = default;
|
||||||
|
Vec2D (const Vec2D& vec);
|
||||||
|
Vec2D (const Point4D& point4D);
|
||||||
|
explicit Vec2D (double x, double y = 0.0);
|
||||||
|
Vec2D& operator=(const Vec2D&) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] double x() const { return _arr_point[0]; }
|
||||||
|
[[nodiscard]] double y() const { return _arr_point[1]; }
|
||||||
|
|
||||||
|
[[nodiscard]] Vec2D operator-() const;
|
||||||
|
|
||||||
|
// Boolean operations
|
||||||
|
bool operator==(const Vec2D& vec) const;
|
||||||
|
bool operator!=(const Vec2D& vec) const;
|
||||||
|
|
||||||
|
[[nodiscard]] Vec2D operator+(const Vec2D& vec) const;
|
||||||
|
[[nodiscard]] Vec2D operator-(const Vec2D& vec) const;
|
||||||
|
|
||||||
|
[[nodiscard]] double dot(const Vec2D& vec) const; // Returns dot product
|
||||||
|
|
||||||
|
// Operations with numbers
|
||||||
|
[[nodiscard]] Vec2D operator*(double number) const;
|
||||||
|
[[nodiscard]] Vec2D operator/(double number) const;
|
||||||
|
|
||||||
|
// Other useful methods
|
||||||
|
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
|
||||||
|
[[nodiscard]] double abs() const; // Returns vector length
|
||||||
|
[[nodiscard]] Vec2D normalized() const; // Returns normalized vector without changing
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SHOOTER_VEC2D_H
|
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// Created by Иван Ильин on 09.10.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Vec3D.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
Vec3D::Vec3D(const Vec3D &vec) {
|
||||||
|
_arr_point[0] = vec.x();
|
||||||
|
_arr_point[1] = vec.y();
|
||||||
|
_arr_point[2] = vec.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D::Vec3D (const Point4D& point4D) {
|
||||||
|
_arr_point[0] = point4D.x();
|
||||||
|
_arr_point[1] = point4D.y();
|
||||||
|
_arr_point[2] = point4D.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D::Vec3D (double x, double y, double z) {
|
||||||
|
_arr_point[0] = x;
|
||||||
|
_arr_point[1] = y;
|
||||||
|
_arr_point[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D Vec3D::operator-() const {
|
||||||
|
return Vec3D(-x(), -y(), -z());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Vec3D::operator==(const Vec3D& vec) const {
|
||||||
|
return (*this - vec).sqrAbs() < Consts::EPS;
|
||||||
|
}
|
||||||
|
bool Vec3D::operator!=(const Vec3D& vec) const {
|
||||||
|
return !(*this == vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Operations with Vec3D
|
||||||
|
Vec3D Vec3D::operator+(const Vec3D& vec) const {
|
||||||
|
return Vec3D(x()+vec.x(), y()+vec.y(), z()+vec.z());
|
||||||
|
}
|
||||||
|
Vec3D Vec3D::operator-(const Vec3D& vec) const {
|
||||||
|
return Vec3D(*this) + -vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D Vec3D::operator*(double number) const {
|
||||||
|
return Vec3D(x()*number, y()*number, z()*number);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D Vec3D::operator/(double number) const {
|
||||||
|
if(std::abs(number) > Consts::EPS)
|
||||||
|
return Vec3D(*this)*(1.0/number);
|
||||||
|
else
|
||||||
|
throw std::domain_error{"Vec3D::operator/(double number): division by zero"};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other useful methods
|
||||||
|
double Vec3D::sqrAbs() const {
|
||||||
|
return x()*x() + y()*y() + z()*z();
|
||||||
|
}
|
||||||
|
|
||||||
|
double Vec3D::abs() const {
|
||||||
|
return sqrt(sqrAbs());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D Vec3D::normalized() const {
|
||||||
|
double vecAbs = abs();
|
||||||
|
if(vecAbs > Consts::EPS)
|
||||||
|
return Vec3D(*this)/abs();
|
||||||
|
else
|
||||||
|
return Vec3D(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Vec3D::dot(const Vec3D& vec) const {
|
||||||
|
return vec.x() * x() + vec.y() * y() + vec.z() * z();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3D Vec3D::cross(const Vec3D& vec) const {
|
||||||
|
return Vec3D{y() * vec.z() - vec.y() * z(),
|
||||||
|
z() * vec.x() - vec.z() * x(),
|
||||||
|
x() * vec.y() - vec.x() * y()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Point4D Vec3D::makePoint4D() const {
|
||||||
|
return Point4D(x(), y(), z(), 1.0);
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
//
|
||||||
|
// Created by Иван Ильин on 09.10.2021.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHOOTER_VEC3D_H
|
||||||
|
#define SHOOTER_VEC3D_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "Point4D.h"
|
||||||
|
|
||||||
|
class Vec3D {
|
||||||
|
private:
|
||||||
|
std::array<double, 3> _arr_point{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vec3D () = default;
|
||||||
|
Vec3D (const Vec3D& vec);
|
||||||
|
explicit Vec3D (const Point4D& vec);
|
||||||
|
explicit Vec3D (double x, double y = 0.0, double z = 0.0);
|
||||||
|
Vec3D& operator=(const Vec3D&) = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] double x() const { return _arr_point[0]; }
|
||||||
|
[[nodiscard]] double y() const { return _arr_point[1]; }
|
||||||
|
[[nodiscard]] double z() const { return _arr_point[2]; }
|
||||||
|
|
||||||
|
[[nodiscard]] Vec3D operator-() const;
|
||||||
|
|
||||||
|
// Boolean operations
|
||||||
|
bool operator==(const Vec3D& vec) const;
|
||||||
|
bool operator!=(const Vec3D& vec) const;
|
||||||
|
|
||||||
|
// Operations with Point4D
|
||||||
|
[[nodiscard]] Vec3D operator+(const Vec3D& vec) const;
|
||||||
|
[[nodiscard]] Vec3D operator-(const Vec3D& vec) const;
|
||||||
|
|
||||||
|
[[nodiscard]] double dot(const Vec3D& vec) const; // Returns dot product
|
||||||
|
[[nodiscard]] Vec3D cross(const Vec3D& vec) const; // Returns cross product
|
||||||
|
|
||||||
|
// Operations with numbers
|
||||||
|
[[nodiscard]] Vec3D operator*(double number) const;
|
||||||
|
[[nodiscard]] Vec3D operator/(double number) const;
|
||||||
|
|
||||||
|
// Other useful methods
|
||||||
|
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
|
||||||
|
[[nodiscard]] double abs() const; // Returns vector length
|
||||||
|
[[nodiscard]] Vec3D normalized() const; // Returns normalized vector without changing
|
||||||
|
[[nodiscard]] Point4D makePoint4D() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //SHOOTER_VEC3D_H
|
|
@ -14,36 +14,39 @@ void World::addBody(std::shared_ptr<RigidBody> body, const string &name) {
|
||||||
Log::log("World::addBody(): inserted body '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
|
Log::log("World::addBody(): inserted body '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::loadBody(const string &name, const string &filename, const std::string &materials, const Point4D& scale) {
|
void World::loadBody(const string &name, const string &filename, const std::string &materials, const Vec3D& scale) {
|
||||||
_objects.emplace(name, std::make_shared<RigidBody>(Mesh(filename, materials, scale)));
|
_objects.emplace(name, std::make_shared<RigidBody>(Mesh(filename, materials, scale)));
|
||||||
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
|
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + name + "' with " + std::to_string(_objects[name]->triangles().size()) + " tris.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Point4D, string> World::rayCast(const Point4D& from, const Point4D& to) {
|
std::pair<Vec3D, string> World::rayCast(const Vec3D& from, const Vec3D& to) {
|
||||||
|
|
||||||
std::pair<Point4D, string> result{Point4D{0, 0,0, -1}, ""};
|
std::pair<Vec3D, string> result;
|
||||||
double minDistance = 10000;
|
std::unique_ptr<Vec3D> point = std::make_unique<Vec3D>();
|
||||||
|
std::string name;
|
||||||
|
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
|
||||||
|
|
||||||
for(auto& object : _objects) {
|
for(auto& object : _objects) {
|
||||||
if((object.first.find("Player") != std::string::npos) || (object.first.find("Bonus") != std::string::npos))
|
if((object.first.find("Player") != std::string::npos) || (object.first.find("Bonus") != std::string::npos))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(auto& tri : object.second->triangles()) {
|
for(auto& tri : object.second->triangles()) {
|
||||||
Triangle tri_translated(tri[0] + object.second->position(), tri[1] + object.second->position(), tri[2] + object.second->position());
|
Triangle tri_translated(tri[0] + object.second->position().makePoint4D(), tri[1] + object.second->position().makePoint4D(), tri[2] + object.second->position().makePoint4D());
|
||||||
|
|
||||||
Plane plane(tri_translated);
|
Plane plane(tri_translated);
|
||||||
auto intersection = plane.intersection(from, to);
|
auto intersection = plane.intersection(from, to);
|
||||||
double distance = (intersection.first - from).sqrAbs();
|
double distance = (intersection.first - from).sqrAbs();
|
||||||
if(intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) {
|
if(intersection.second > 0 && distance < minDistance && tri_translated.isPointInside(intersection.first)) {
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
result = {intersection.first, object.first};
|
point = std::make_unique<Vec3D>(intersection.first);
|
||||||
|
name = object.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return {*point, name};
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::loadMap(const std::string& filename, const std::string& materials, const std::string& name, const Point4D& scale) {
|
void World::loadMap(const std::string& filename, const std::string& materials, const std::string& name, const Vec3D& scale) {
|
||||||
auto objs = Mesh::LoadObjects(filename, materials, scale);
|
auto objs = Mesh::LoadObjects(filename, materials, scale);
|
||||||
for(unsigned i = 0; i < objs.size(); i++) {
|
for(unsigned i = 0; i < objs.size(); i++) {
|
||||||
string meshName = name + "_" + to_string(i);
|
string meshName = name + "_" + to_string(i);
|
||||||
|
|
|
@ -22,14 +22,14 @@ public:
|
||||||
void addBody(std::shared_ptr<RigidBody> mesh, const std::string& name = "");
|
void addBody(std::shared_ptr<RigidBody> mesh, const std::string& name = "");
|
||||||
std::shared_ptr<RigidBody> body(const std::string& name);
|
std::shared_ptr<RigidBody> body(const std::string& name);
|
||||||
void removeBody(std::string name);
|
void removeBody(std::string name);
|
||||||
void loadBody(const std::string &name, const std::string &filename, const std::string &materials = "", const Point4D& scale = Point4D{1, 1, 1});
|
void loadBody(const std::string &name, const std::string &filename, const std::string &materials = "", const Vec3D& scale = Vec3D{1, 1, 1});
|
||||||
|
|
||||||
// rayCast returns pair of Point4D and std::string:
|
// rayCast returns pair of Point4D and std::string:
|
||||||
// 1) Point4D is point of collision (the last coordinate is -1 if there are no collisions)
|
// 1) Point4D is point of collision
|
||||||
// 2) std::string - title of the object
|
// 2) std::string - title of the object
|
||||||
std::pair<Point4D, std::string> rayCast(const Point4D& from, const Point4D& to);
|
std::pair<Vec3D, std::string> rayCast(const Vec3D& from, const Vec3D& to);
|
||||||
|
|
||||||
void loadMap(const std::string& filename, const std::string& materials, const std::string& name = "map", const Point4D & scale = Point4D{1, 1, 1});
|
void loadMap(const std::string& filename, const std::string& materials, const std::string& name = "map", const Vec3D & scale = Vec3D{1, 1, 1});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,13 @@ class ARotate : public Animation {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Object> _object;
|
std::shared_ptr<Object> _object;
|
||||||
|
|
||||||
Point4D value;
|
Vec3D value;
|
||||||
public:
|
public:
|
||||||
ARotate(std::shared_ptr<Object> object, const Point4D& r, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) {
|
ARotate(std::shared_ptr<Object> object, const Vec3D& r, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(r) {
|
||||||
_object = object;
|
_object = object;
|
||||||
_duration = duration;
|
_duration = duration;
|
||||||
_looped = looped;
|
_looped = looped;
|
||||||
_intType = interpolationType;
|
_intType = interpolationType;
|
||||||
|
|
||||||
value = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update() override {
|
bool update() override {
|
||||||
|
|
|
@ -13,17 +13,15 @@ class AScale : public Animation {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Mesh> _mesh;
|
std::shared_ptr<Mesh> _mesh;
|
||||||
|
|
||||||
Point4D value;
|
Vec3D value;
|
||||||
std::vector<Triangle> triangles{};
|
std::vector<Triangle> triangles{};
|
||||||
public:
|
public:
|
||||||
AScale(std::shared_ptr<Mesh> mesh, const Point4D &s, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) {
|
AScale(std::shared_ptr<Mesh> mesh, const Vec3D &s, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(s) {
|
||||||
_mesh = mesh;
|
_mesh = mesh;
|
||||||
_duration = duration;
|
_duration = duration;
|
||||||
_looped = looped;
|
_looped = looped;
|
||||||
_intType = interpolationType;
|
_intType = interpolationType;
|
||||||
_waitFor = true;
|
_waitFor = true;
|
||||||
|
|
||||||
value = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update() override {
|
bool update() override {
|
||||||
|
|
|
@ -12,15 +12,13 @@ class ATranslate : public Animation {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Object> _object;
|
std::shared_ptr<Object> _object;
|
||||||
|
|
||||||
Point4D value;
|
Vec3D value;
|
||||||
public:
|
public:
|
||||||
ATranslate(std::shared_ptr<Object> object, const Point4D& t, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) {
|
ATranslate(std::shared_ptr<Object> object, const Vec3D& t, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : value(t){
|
||||||
_object = object;
|
_object = object;
|
||||||
_duration = duration;
|
_duration = duration;
|
||||||
_looped = looped;
|
_looped = looped;
|
||||||
_intType = interpolationType;
|
_intType = interpolationType;
|
||||||
|
|
||||||
value = t;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update() override {
|
bool update() override {
|
||||||
|
|
|
@ -12,23 +12,21 @@ class ATranslateToPoint : public Animation {
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Object> _object;
|
std::shared_ptr<Object> _object;
|
||||||
|
|
||||||
Point4D point;
|
Vec3D point;
|
||||||
Point4D value;
|
std::unique_ptr<Vec3D> value;
|
||||||
public:
|
public:
|
||||||
ATranslateToPoint(std::shared_ptr<Object> object, const Point4D& p, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) {
|
ATranslateToPoint(std::shared_ptr<Object> object, const Vec3D& p, double duration = 1, LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::bezier) : point(p) {
|
||||||
_object = object;
|
_object = object;
|
||||||
_duration = duration;
|
_duration = duration;
|
||||||
_looped = looped;
|
_looped = looped;
|
||||||
_intType = interpolationType;
|
_intType = interpolationType;
|
||||||
|
|
||||||
point = p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update() override {
|
bool update() override {
|
||||||
if(!_started) {
|
if(!_started) {
|
||||||
value = point - _object->position();
|
value = std::make_unique<Vec3D>(point - _object->position());
|
||||||
}
|
}
|
||||||
_object->translate(value * _dp);
|
_object->translate(*value * _dp);
|
||||||
|
|
||||||
return updateState();
|
return updateState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ bool Animation::updateState() {
|
||||||
|
|
||||||
switch (_intType) {
|
switch (_intType) {
|
||||||
case InterpolationType::bezier:
|
case InterpolationType::bezier:
|
||||||
_p = Interpolation::Bezier(_bezier[0], _bezier[1], _time);
|
_p = Interpolation::Bezier(*_bezier[0], *_bezier[1], _time);
|
||||||
_dp = Interpolation::dBezier(_bezier[0], _bezier[1], _time, _dtime);
|
_dp = Interpolation::dBezier(*_bezier[0], *_bezier[1], _time, _dtime);
|
||||||
break;
|
break;
|
||||||
case InterpolationType::bouncing:
|
case InterpolationType::bouncing:
|
||||||
_p = Interpolation::Bouncing(_time);
|
_p = Interpolation::Bouncing(_time);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "../utils/Time.h"
|
#include "../utils/Time.h"
|
||||||
#include "../Triangle.h"
|
#include "../Triangle.h"
|
||||||
#include "Interpolation.h"
|
#include "Interpolation.h"
|
||||||
|
#include "../Vec2D.h"
|
||||||
|
|
||||||
class Animation {
|
class Animation {
|
||||||
public:
|
public:
|
||||||
|
@ -37,7 +38,8 @@ protected:
|
||||||
double _dp = 0;
|
double _dp = 0;
|
||||||
|
|
||||||
InterpolationType _intType = InterpolationType::bezier;
|
InterpolationType _intType = InterpolationType::bezier;
|
||||||
Point4D _bezier[2] = {Point4D{0.8, 0}, Point4D{0.2, 1}};
|
std::unique_ptr<Vec2D> _bezier[2] = {std::make_unique<Vec2D>(Vec2D{0.8, 0}),
|
||||||
|
std::make_unique<Vec2D>(Vec2D{0.2, 1})};
|
||||||
|
|
||||||
// If '_waitFor' == true then we need to finish all animation before starting this one. (for example for a_wait() or a_scale())
|
// If '_waitFor' == true then we need to finish all animation before starting this one. (for example for a_wait() or a_scale())
|
||||||
bool _waitFor = false;
|
bool _waitFor = false;
|
||||||
|
@ -47,7 +49,10 @@ public:
|
||||||
Animation() = default;
|
Animation() = default;
|
||||||
virtual ~Animation() = default;
|
virtual ~Animation() = default;
|
||||||
|
|
||||||
void setBezierParams(const Point4D& p1, const Point4D& p2) { _bezier[0] = p1; _bezier[1] = p2; }
|
void setBezierPoints(const Vec2D& p1, const Vec2D& p2) {
|
||||||
|
_bezier[0] = std::make_unique<Vec2D>(p1);
|
||||||
|
_bezier[1] = std::make_unique<Vec2D>(p2);
|
||||||
|
}
|
||||||
[[nodiscard]] bool waitFor() const { return _waitFor; }
|
[[nodiscard]] bool waitFor() const { return _waitFor; }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef ENGINE_INTERPOLATION_H
|
#ifndef ENGINE_INTERPOLATION_H
|
||||||
#define ENGINE_INTERPOLATION_H
|
#define ENGINE_INTERPOLATION_H
|
||||||
|
|
||||||
#include "../utils/Point4D.h"
|
#include "../Vec2D.h"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "../Consts.h"
|
#include "../Consts.h"
|
||||||
|
@ -13,12 +13,12 @@
|
||||||
namespace Interpolation {
|
namespace Interpolation {
|
||||||
static double Linear(double t);
|
static double Linear(double t);
|
||||||
static double Cos(double t);
|
static double Cos(double t);
|
||||||
static double Bezier(const Point4D& p1, const Point4D& p2, double t);
|
static double Bezier(const Vec2D& p1, const Vec2D& p2, double t);
|
||||||
static double Bouncing(double t);
|
static double Bouncing(double t);
|
||||||
|
|
||||||
static double dLinear(double t, double dt);
|
static double dLinear(double t, double dt);
|
||||||
static double dCos(double t, double dt);
|
static double dCos(double t, double dt);
|
||||||
static double dBezier(const Point4D& p1, const Point4D& p2, double t, double dt);
|
static double dBezier(const Vec2D& p1, const Vec2D& p2, double t, double dt);
|
||||||
static double dBouncing(double t, double dt);
|
static double dBouncing(double t, double dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,11 +32,11 @@ double Interpolation::Cos(double t) {
|
||||||
return 0.5*(1 - cos(Consts::PI*Interpolation::Linear(t)));
|
return 0.5*(1 - cos(Consts::PI*Interpolation::Linear(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
double Interpolation::Bezier(const Point4D &p1, const Point4D &p2, double t) {
|
double Interpolation::Bezier(const Vec2D &p1, const Vec2D &p2, double t) {
|
||||||
t = Interpolation::Linear(t);
|
t = Interpolation::Linear(t);
|
||||||
|
|
||||||
double h = 0.000001;
|
double h = Consts::EPS;
|
||||||
double eps = 0.000001;
|
double eps = Consts::EPS;
|
||||||
|
|
||||||
// We are trying to find 's' when px = t
|
// We are trying to find 's' when px = t
|
||||||
auto f = [=](double s){
|
auto f = [=](double s){
|
||||||
|
@ -77,7 +77,7 @@ double Interpolation::dCos(double t, double dt) {
|
||||||
return 0.5*Consts::PI*sin(Consts::PI*t)*dt;
|
return 0.5*Consts::PI*sin(Consts::PI*t)*dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Interpolation::dBezier(const Point4D &p1, const Point4D &p2, double t, double dt) {
|
double Interpolation::dBezier(const Vec2D &p1, const Vec2D &p2, double t, double dt) {
|
||||||
return Interpolation::Bezier(p1, p2, t + dt) - Interpolation::Bezier(p1, p2, t);
|
return Interpolation::Bezier(p1, p2, t + dt) - Interpolation::Bezier(p1, p2, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ void Window::update() {
|
||||||
_screen->setTitle(_name);
|
_screen->setTitle(_name);
|
||||||
_screen->drawSprite(_back);
|
_screen->drawSprite(_back);
|
||||||
|
|
||||||
Point4D mousePos = _mouse->getMousePosition();
|
Vec2D mousePos = _mouse->getMousePosition();
|
||||||
Point4D dMousePos = mousePos - _prevMousePosition;
|
Vec2D dMousePos = mousePos - *_prevMousePosition;
|
||||||
_back.setPosition(_back.getPosition() - sf::Vector2f((float)(dMousePos.x() / 30), (float)(dMousePos.y() / 30)));
|
_back.setPosition(_back.getPosition() - sf::Vector2f((float)(dMousePos.x() / 30), (float)(dMousePos.y() / 30)));
|
||||||
bool isPressed = _mouse->isButtonTapped(sf::Mouse::Left);
|
bool isPressed = _mouse->isButtonTapped(sf::Mouse::Left);
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ void Window::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_prevMousePosition = mousePos;
|
_prevMousePosition = std::make_unique<Vec2D>(mousePos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::setBackgroundTexture(const std::string &texture, double sx, double sy, int w, int h) {
|
void Window::setBackgroundTexture(const std::string &texture, double sx, double sy, int w, int h) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ private:
|
||||||
|
|
||||||
sf::Sprite _back;
|
sf::Sprite _back;
|
||||||
|
|
||||||
Point4D _prevMousePosition;
|
std::unique_ptr<Vec2D> _prevMousePosition = std::make_unique<Vec2D>(Vec2D{0, 0});
|
||||||
|
|
||||||
std::shared_ptr<Screen> _screen;
|
std::shared_ptr<Screen> _screen;
|
||||||
std::shared_ptr<Mouse> _mouse;
|
std::shared_ptr<Mouse> _mouse;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "../utils/Log.h"
|
#include "../utils/Log.h"
|
||||||
|
|
||||||
ClientUDP::ClientUDP() : _lastBroadcast(std::numeric_limits<double>::min()), _working(false)
|
ClientUDP::ClientUDP() : _lastBroadcast(-std::numeric_limits<double>::max()), _working(false)
|
||||||
{
|
{
|
||||||
_socket.setTimeoutCallback(std::bind(&ClientUDP::timeout, this, std::placeholders::_1));
|
_socket.setTimeoutCallback(std::bind(&ClientUDP::timeout, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include "../utils/Time.h"
|
#include "../utils/Time.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
ReliableMsg::ReliableMsg(sf::Packet& packet, sf::IpAddress address, sf::Uint16 port) : packet(packet), address(address), port(port), lastTry(std::numeric_limits<double>::min()), firstTry(Time::time()) {}
|
ReliableMsg::ReliableMsg(sf::Packet& packet, sf::IpAddress address, sf::Uint16 port) : packet(packet), address(address), port(port), lastTry(-std::numeric_limits<double>::max()), firstTry(Time::time()) {}
|
||||||
ReliableMsg::ReliableMsg(const ReliableMsg& msg) : packet(msg.packet), address(msg.address), port(msg.port), lastTry(msg.lastTry), firstTry(msg.firstTry) {}
|
ReliableMsg::ReliableMsg(const ReliableMsg& msg) : packet(msg.packet), address(msg.address), port(msg.port), lastTry(msg.lastTry), firstTry(msg.firstTry) {}
|
||||||
|
|
||||||
bool ReliableMsg::trySend(sf::UdpSocket& socket)
|
bool ReliableMsg::trySend(sf::UdpSocket& socket)
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "../utils/Log.h"
|
#include "../utils/Log.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
ServerUDP::ServerUDP() : _lastBroadcast(std::numeric_limits<double>::min()), _working(false)
|
ServerUDP::ServerUDP() : _lastBroadcast(-std::numeric_limits<double>::max()), _working(false)
|
||||||
{
|
{
|
||||||
_socket.setTimeoutCallback(std::bind(&ServerUDP::timeout, this, std::placeholders::_1));
|
_socket.setTimeoutCallback(std::bind(&ServerUDP::timeout, this, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,167 +9,171 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
Point4D RigidBody::_findFurthestPoint(const Point4D& direction) {
|
Vec3D RigidBody::_findFurthestPoint(const Vec3D& direction) {
|
||||||
Point4D maxPoint = {};
|
std::unique_ptr<Vec3D> maxPoint = std::make_unique<Vec3D>(Vec3D{0, 0, 0});
|
||||||
auto maxDistance = (double)-INFINITY;
|
auto maxDistance = -std::numeric_limits<double>::max();
|
||||||
for(auto& tri : triangles()){
|
for(auto& tri : triangles()){
|
||||||
for(int i = 0; i < 3; i++){
|
for(int i = 0; i < 3; i++){
|
||||||
Point4D point = tri[i];
|
Vec3D point = Vec3D(tri[i] + position().makePoint4D());
|
||||||
|
|
||||||
point = point + position();
|
|
||||||
|
|
||||||
double distance = point.dot(direction);
|
double distance = point.dot(direction);
|
||||||
if(distance > maxDistance) {
|
if(distance > maxDistance) {
|
||||||
maxDistance = distance;
|
maxDistance = distance;
|
||||||
maxPoint = point;
|
maxPoint = std::make_unique<Vec3D>(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return maxPoint;
|
return *maxPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D RigidBody::_support(std::shared_ptr<RigidBody> obj, const Point4D& direction) {
|
Vec3D RigidBody::_support(std::shared_ptr<RigidBody> obj, const Vec3D& direction) {
|
||||||
Point4D p1 = _findFurthestPoint(direction);
|
Vec3D p1 = _findFurthestPoint(direction);
|
||||||
Point4D p2 = obj->_findFurthestPoint(-direction);
|
Vec3D p2 = obj->_findFurthestPoint(-direction);
|
||||||
|
|
||||||
return p1 - p2;
|
return p1 - p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RigidBody::_nextSimplex(Simplex &points, Point4D &direction) {
|
NextSimplex RigidBody::_nextSimplex(const Simplex &points) {
|
||||||
switch (points.size()) {
|
switch (points.type()) {
|
||||||
case 2: return _line(points, direction);
|
case SimplexType::Line: return _lineCase(points);
|
||||||
case 3: return _triangle(points, direction);
|
case SimplexType::Triangle: return _triangleCase(points);
|
||||||
case 4: return _tetrahedron(points, direction);
|
case SimplexType::Tetrahedron: return _tetrahedronCase(points);
|
||||||
|
|
||||||
|
default: throw std::logic_error{"RigidBody::_nextSimplex: simplex is not Line, Triangle or Tetrahedron"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// never should be here
|
NextSimplex RigidBody::_lineCase(const Simplex& points) {
|
||||||
return false;
|
std::unique_ptr<Simplex> newPoints = std::make_unique<Simplex>(points);
|
||||||
}
|
std::unique_ptr<Vec3D> newDirection;
|
||||||
|
|
||||||
bool RigidBody::_line(Simplex& points, Point4D& direction) {
|
Vec3D a = points[0];
|
||||||
Point4D a = points[0];
|
Vec3D b = points[1];
|
||||||
Point4D b = points[1];
|
|
||||||
|
|
||||||
Point4D ab = b - a;
|
Vec3D ab = b - a;
|
||||||
Point4D ao = - a;
|
Vec3D ao = - a;
|
||||||
|
|
||||||
if (ab.dot(ao) > 0) {
|
if (ab.dot(ao) > 0) {
|
||||||
direction = ab.cross3D(ao).cross3D(ab);
|
newDirection = std::make_unique<Vec3D>(ab.cross(ao).cross(ab));
|
||||||
} else {
|
} else {
|
||||||
points = { a };
|
newPoints = std::make_unique<Simplex>(Simplex{a});
|
||||||
direction = ao;
|
newDirection = std::make_unique<Vec3D>(ao);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return NextSimplex{*newPoints, *newDirection, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RigidBody::_triangle(Simplex &points, Point4D &direction) {
|
NextSimplex RigidBody::_triangleCase(const Simplex &points) {
|
||||||
Point4D a = points[0];
|
std::unique_ptr<Simplex> newPoints = std::make_unique<Simplex>(points);
|
||||||
Point4D b = points[1];
|
std::unique_ptr<Vec3D> newDirection;
|
||||||
Point4D c = points[2];
|
|
||||||
|
|
||||||
Point4D ab = b - a;
|
Vec3D a = points[0];
|
||||||
Point4D ac = c - a;
|
Vec3D b = points[1];
|
||||||
Point4D ao = - a;
|
Vec3D c = points[2];
|
||||||
|
|
||||||
Point4D abc = ab.cross3D(ac);
|
Vec3D ab = b - a;
|
||||||
|
Vec3D ac = c - a;
|
||||||
|
Vec3D ao = - a;
|
||||||
|
|
||||||
if (abc.cross3D(ac).dot(ao) > 0) {
|
Vec3D abc = ab.cross(ac);
|
||||||
|
|
||||||
|
if (abc.cross(ac).dot(ao) > 0) {
|
||||||
if (ac.dot(ao) > 0) {
|
if (ac.dot(ao) > 0) {
|
||||||
points = { a, c };
|
newPoints = std::make_unique<Simplex>(Simplex{ a, c });
|
||||||
direction = ac.cross3D(ao).cross3D(ac);
|
newDirection = std::make_unique<Vec3D>(ac.cross(ao).cross(ac));
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
return _lineCase(Simplex { a, b });
|
||||||
return _line(points = { a, b }, direction);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ab.cross3D(abc).dot(ao) > 0) {
|
|
||||||
return _line(points = { a, b }, direction);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (abc.dot(ao) > 0) {
|
|
||||||
direction = abc;
|
|
||||||
} else {
|
} else {
|
||||||
points = { a, c, b };
|
if (ab.cross(abc).dot(ao) > 0) {
|
||||||
direction = -abc;
|
return _lineCase(Simplex { a, b });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (abc.dot(ao) > 0) {
|
||||||
|
newDirection = std::make_unique<Vec3D>(abc);
|
||||||
|
} else {
|
||||||
|
newPoints = std::make_unique<Simplex>(Simplex{ a, c, b });
|
||||||
|
newDirection = std::make_unique<Vec3D>(-abc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return NextSimplex{*newPoints, *newDirection, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RigidBody::_tetrahedron(Simplex &points, Point4D &direction) {
|
NextSimplex RigidBody::_tetrahedronCase(const Simplex &points) {
|
||||||
Point4D a = points[0];
|
Vec3D a = points[0];
|
||||||
Point4D b = points[1];
|
Vec3D b = points[1];
|
||||||
Point4D c = points[2];
|
Vec3D c = points[2];
|
||||||
Point4D d = points[3];
|
Vec3D d = points[3];
|
||||||
|
|
||||||
Point4D ab = b - a;
|
Vec3D ab = b - a;
|
||||||
Point4D ac = c - a;
|
Vec3D ac = c - a;
|
||||||
Point4D ad = d - a;
|
Vec3D ad = d - a;
|
||||||
Point4D ao = - a;
|
Vec3D ao = - a;
|
||||||
|
|
||||||
Point4D abc = ab.cross3D(ac);
|
Vec3D abc = ab.cross(ac);
|
||||||
Point4D acd = ac.cross3D(ad);
|
Vec3D acd = ac.cross(ad);
|
||||||
Point4D adb = ad.cross3D(ab);
|
Vec3D adb = ad.cross(ab);
|
||||||
|
|
||||||
if (abc.dot(ao) > 0) {
|
if (abc.dot(ao) > 0) {
|
||||||
return _triangle(points = { a, b, c }, direction);
|
return _triangleCase(Simplex{ a, b, c });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acd.dot(ao) > 0) {
|
if (acd.dot(ao) > 0) {
|
||||||
return _triangle(points = { a, c, d }, direction);
|
return _triangleCase(Simplex{ a, c, d });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adb.dot(ao) > 0) {
|
if (adb.dot(ao) > 0) {
|
||||||
return _triangle(points = { a, d, b }, direction);
|
return _triangleCase(Simplex{ a, d, b });
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return NextSimplex{points, Vec3D(), true};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, Simplex> RigidBody::checkGJKCollision(std::shared_ptr<RigidBody> obj) {
|
std::pair<bool, Simplex> RigidBody::checkGJKCollision(std::shared_ptr<RigidBody> obj) {
|
||||||
|
|
||||||
// Get initial support point in any direction
|
// Get initial support point in any direction
|
||||||
Point4D support = _support(obj, Point4D{1, 0, 0});
|
std::unique_ptr<Vec3D> support = std::make_unique<Vec3D>(_support(obj, Vec3D{1, 0, 0}));
|
||||||
|
|
||||||
// Simplex is an array of points, max count is 4
|
// Simplex is an array of points, max count is 4
|
||||||
Simplex points;
|
std::unique_ptr<Simplex> points = std::make_unique<Simplex>();
|
||||||
points.push_front(support);
|
points->push_front(*support);
|
||||||
|
|
||||||
// New direction is towards the origin
|
// New direction is towards the origin
|
||||||
Point4D direction = -support;
|
std::unique_ptr<Vec3D> direction = std::make_unique<Vec3D>(-*support);
|
||||||
|
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
|
|
||||||
while (iterations < 50) {
|
while (iterations < Consts::GJK_MAX_ITERATIONS) {
|
||||||
support = _support(obj, direction);
|
support = std::make_unique<Vec3D>(_support(obj, *direction));
|
||||||
|
|
||||||
if (support.dot(direction) <= 0)
|
if (support->dot(*direction) <= 0)
|
||||||
return std::make_pair(false, points); // no collision
|
return std::make_pair(false, *points); // no collision
|
||||||
|
|
||||||
points.push_front(support);
|
points->push_front(*support);
|
||||||
|
|
||||||
if (_nextSimplex(points, direction)) {
|
NextSimplex nextSimplex = _nextSimplex(*points);
|
||||||
|
|
||||||
|
direction = std::make_unique<Vec3D>(nextSimplex.newDirection);
|
||||||
|
points = std::make_unique<Simplex>(nextSimplex.newSimplex);
|
||||||
|
|
||||||
|
if (nextSimplex.finishSearching) {
|
||||||
if(obj->isCollider())
|
if(obj->isCollider())
|
||||||
_inCollision = true;
|
_inCollision = true;
|
||||||
return std::make_pair(true, points);
|
return std::make_pair(true, *points);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterations++;
|
iterations++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(false, points); // no collision
|
return std::make_pair(false, *points); // no collision
|
||||||
}
|
}
|
||||||
|
|
||||||
CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj) {
|
CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj) {
|
||||||
|
|
||||||
std::vector<Point4D> polytope(simplex.begin(), simplex.end());
|
std::vector<Vec3D> polytope(simplex.begin(), simplex.end());
|
||||||
std::vector<size_t> faces = {
|
std::vector<size_t> faces = {
|
||||||
0, 1, 2,
|
0, 1, 2,
|
||||||
0, 3, 1,
|
0, 3, 1,
|
||||||
|
@ -178,41 +182,39 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
|
||||||
};
|
};
|
||||||
|
|
||||||
// list: vector4(normal, distance), index: min distance
|
// list: vector4(normal, distance), index: min distance
|
||||||
auto [normals, minFace] = _getFaceNormals(polytope, faces);
|
auto [normals, minFace] = std::move(_getFaceNormals(polytope, faces));
|
||||||
|
|
||||||
Point4D minNormal;
|
std::shared_ptr<Vec3D> minNormal{};
|
||||||
double minDistance = INFINITY;
|
double minDistance = std::numeric_limits<double>::max();
|
||||||
|
|
||||||
int iterations = 0;
|
int iterations = 0;
|
||||||
|
|
||||||
while ((minDistance == INFINITY) && (iterations < 50)) {
|
while ((minDistance == std::numeric_limits<double>::max()) && (iterations < Consts::GJK_MAX_ITERATIONS)) {
|
||||||
minNormal = Point4D{normals[minFace].x(), normals[minFace].y(), normals[minFace].z()};
|
minNormal = std::make_shared<Vec3D>(normals[minFace]->normal);
|
||||||
minDistance = normals[minFace].w();
|
minDistance = normals[minFace]->distance;
|
||||||
|
|
||||||
Point4D support = _support(obj, minNormal);
|
Vec3D support = _support(obj, *minNormal);
|
||||||
double sDistance = minNormal.dot(support);
|
double sDistance = minNormal->dot(support);
|
||||||
|
|
||||||
if (std::abs(sDistance - minDistance) > 0.0001) {
|
if (std::abs(sDistance - minDistance) > Consts::EPA_EPS) {
|
||||||
minDistance = INFINITY;
|
minDistance = std::numeric_limits<double>::max();
|
||||||
std::vector<std::pair<size_t, size_t>> uniqueEdges;
|
std::vector<std::pair<size_t, size_t>> uniqueEdges;
|
||||||
|
|
||||||
for (size_t i = 0; i < normals.size(); i++) {
|
for (size_t i = 0; i < normals.size(); i++) {
|
||||||
if (normals[i].dot(support) > 0) {
|
if (normals[i]->normal.dot(support) > 0) {
|
||||||
size_t f = i * 3;
|
size_t f = i * 3;
|
||||||
|
|
||||||
_addIfUniqueEdge(uniqueEdges, faces, f, f + 1);
|
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 0, f + 1);
|
||||||
_addIfUniqueEdge(uniqueEdges, faces, f + 1, f + 2);
|
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 1, f + 2);
|
||||||
_addIfUniqueEdge(uniqueEdges, faces, f + 2, f);
|
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 2, f + 0);
|
||||||
|
|
||||||
faces[f + 2] = faces.back(); faces.pop_back();
|
faces.erase(faces.begin() + f);
|
||||||
faces[f + 1] = faces.back(); faces.pop_back();
|
faces.erase(faces.begin() + f);
|
||||||
faces[f ] = faces.back(); faces.pop_back();
|
faces.erase(faces.begin() + f);
|
||||||
|
normals.erase(normals.begin() + i--);
|
||||||
normals[i] = normals.back(); normals.pop_back();
|
|
||||||
|
|
||||||
i--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<size_t> newFaces;
|
std::vector<size_t> newFaces;
|
||||||
for (auto [edgeIndex1, edgeIndex2] : uniqueEdges) {
|
for (auto [edgeIndex1, edgeIndex2] : uniqueEdges) {
|
||||||
newFaces.push_back(edgeIndex1);
|
newFaces.push_back(edgeIndex1);
|
||||||
|
@ -227,15 +229,15 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
|
||||||
if(newNormals.empty())
|
if(newNormals.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
double oldMinDistance = INFINITY;
|
double oldMinDistance = std::numeric_limits<double>::max();
|
||||||
for (size_t i = 0; i < normals.size(); i++) {
|
for (size_t i = 0; i < normals.size(); i++) {
|
||||||
if (normals[i].w() < oldMinDistance) {
|
if (normals[i]->distance < oldMinDistance) {
|
||||||
oldMinDistance = normals[i].w();
|
oldMinDistance = normals[i]->distance;
|
||||||
minFace = i;
|
minFace = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newNormals[newMinFace].w() < oldMinDistance) {
|
if (newNormals[newMinFace]->distance < oldMinDistance) {
|
||||||
minFace = newMinFace + normals.size();
|
minFace = newMinFace + normals.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,79 +246,80 @@ CollisionPoint RigidBody::EPA(const Simplex& simplex, std::shared_ptr<RigidBody>
|
||||||
}
|
}
|
||||||
iterations++;
|
iterations++;
|
||||||
}
|
}
|
||||||
CollisionPoint point;
|
|
||||||
|
|
||||||
point.normal = minNormal;
|
|
||||||
point.depth = minDistance + 0.0001;
|
|
||||||
point.hasCollision = minDistance < INFINITY;
|
|
||||||
|
|
||||||
_collisionNormal = minNormal;
|
_collisionNormal = minNormal;
|
||||||
|
return CollisionPoint{*minNormal, minDistance + Consts::EPA_EPS, minDistance < std::numeric_limits<double>::max()};
|
||||||
return point;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<std::vector<Point4D>, size_t> RigidBody::_getFaceNormals(const std::vector<Point4D>& polytope, const std::vector<size_t>& faces) {
|
std::pair<std::vector<std::shared_ptr<FaceNormal>>, size_t> RigidBody::_getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces) {
|
||||||
std::vector<Point4D> normals;
|
std::vector<std::shared_ptr<FaceNormal>> normals;
|
||||||
size_t minTriangle = 0;
|
size_t nearestFaceIndex = 0;
|
||||||
double minDistance = INFINITY;
|
|
||||||
|
double minDistance = std::numeric_limits<double>::max();
|
||||||
|
|
||||||
for (size_t i = 0; i < faces.size(); i += 3) {
|
for (size_t i = 0; i < faces.size(); i += 3) {
|
||||||
Point4D a = polytope[faces[i ]];
|
Vec3D a = polytope[faces[i + 0]];
|
||||||
Point4D b = polytope[faces[i + 1]];
|
Vec3D b = polytope[faces[i + 1]];
|
||||||
Point4D c = polytope[faces[i + 2]];
|
Vec3D c = polytope[faces[i + 2]];
|
||||||
|
|
||||||
Point4D normal = (b - a).cross3D(c - a).normalized();
|
std::shared_ptr<Vec3D> normal = std::make_shared<Vec3D>((b - a).cross(c - a).normalized());
|
||||||
double distance = normal.dot(a);
|
if(normal->sqrAbs() < Consts::EPS)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
double distance = normal->dot(a);
|
||||||
|
|
||||||
if (distance < 0) {
|
if (distance < 0) {
|
||||||
normal = -normal;
|
normal = std::make_unique<Vec3D>(-*normal);
|
||||||
distance *= -1;
|
distance *= -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
normal = Point4D{normal.x(), normal.y(), normal.z(), distance};
|
normal = std::make_shared<Vec3D>(Vec3D{normal->x(), normal->y(), normal->z()});
|
||||||
normals.emplace_back(normal);
|
normals.emplace_back(std::make_shared<FaceNormal>(FaceNormal{*normal, distance}));
|
||||||
|
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
minTriangle = i / 3;
|
nearestFaceIndex = i / 3;
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { normals, minTriangle };
|
return {normals, nearestFaceIndex};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::_addIfUniqueEdge(std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b) {
|
std::vector<std::pair<size_t, size_t>> RigidBody::_addIfUniqueEdge(const std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b) {
|
||||||
|
|
||||||
auto reverse = std::find( // 0--<--3
|
std::vector<std::pair<size_t, size_t>> newEdges = edges;
|
||||||
edges.begin(), // / \ B / A: 2-0
|
|
||||||
edges.end(), // / A \ / B: 0-2
|
|
||||||
std::make_pair(faces[b], faces[a]) // 1-->--2
|
|
||||||
);
|
|
||||||
|
|
||||||
if (reverse != edges.end()) {
|
// We are interested in reversed edge
|
||||||
edges.erase(reverse);
|
// 0--<--3
|
||||||
|
// / \ B / A: 2-0
|
||||||
|
// / A \ / B: 0-2
|
||||||
|
// 1-->--2
|
||||||
|
auto reverse = std::find(newEdges.begin(), newEdges.end(), std::make_pair(faces[b], faces[a]));
|
||||||
|
|
||||||
|
if (reverse != newEdges.end()) {
|
||||||
|
newEdges.erase(reverse);
|
||||||
|
} else {
|
||||||
|
newEdges.emplace_back(faces[a], faces[b]);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
return newEdges;
|
||||||
edges.emplace_back(faces[a], faces[b]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::updatePhysicsState() {
|
void RigidBody::updatePhysicsState() {
|
||||||
translate(_velocity * Time::deltaTime());
|
translate(*_velocity * Time::deltaTime());
|
||||||
_velocity = _velocity + _acceleration * Time::deltaTime();
|
_velocity = std::make_unique<Vec3D>(*_velocity + *_acceleration * Time::deltaTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::setVelocity(const Point4D& velocity) {
|
void RigidBody::setVelocity(const Vec3D& velocity) {
|
||||||
_velocity = velocity;
|
_velocity = std::make_unique<Vec3D>(velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::addVelocity(const Point4D &velocity) {
|
void RigidBody::addVelocity(const Vec3D &velocity) {
|
||||||
_velocity = _velocity + velocity;
|
_velocity = std::make_unique<Vec3D>(*_velocity + velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RigidBody::setAcceleration(const Point4D& acceleration) {
|
void RigidBody::setAcceleration(const Vec3D& acceleration) {
|
||||||
_acceleration = acceleration;
|
_acceleration = std::make_unique<Vec3D>(acceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
RigidBody::RigidBody(const Mesh &mesh) : Mesh(mesh) {
|
RigidBody::RigidBody(const Mesh &mesh) : Mesh(mesh) {
|
||||||
|
|
|
@ -8,52 +8,60 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include "../utils/Point4D.h"
|
|
||||||
#include "../Triangle.h"
|
#include "../Triangle.h"
|
||||||
#include "Simplex.h"
|
#include "Simplex.h"
|
||||||
#include "../Mesh.h"
|
#include "../Mesh.h"
|
||||||
|
|
||||||
struct CollisionPoint {
|
struct CollisionPoint {
|
||||||
Point4D a; // Furthest point of a into b
|
const Vec3D normal;
|
||||||
Point4D b; // Furthest point of b into a
|
const double depth;
|
||||||
Point4D normal; // b – a normalized
|
const bool hasCollision;
|
||||||
double depth; // Length of b – a
|
};
|
||||||
bool hasCollision;
|
|
||||||
|
struct FaceNormal {
|
||||||
|
const Vec3D normal;
|
||||||
|
const double distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NextSimplex {
|
||||||
|
const Simplex newSimplex;
|
||||||
|
const Vec3D newDirection;
|
||||||
|
const bool finishSearching;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RigidBody : public Mesh {
|
class RigidBody : public Mesh {
|
||||||
private:
|
private:
|
||||||
Point4D _findFurthestPoint(const Point4D& direction);
|
Vec3D _findFurthestPoint(const Vec3D& direction);
|
||||||
Point4D _support(std::shared_ptr<RigidBody> obj, const Point4D& direction);
|
Vec3D _support(std::shared_ptr<RigidBody> obj, const Vec3D& direction);
|
||||||
|
|
||||||
std::function<void(const std::string&, std::shared_ptr<RigidBody>)> _collisionCallBack;
|
std::function<void(const std::string&, std::shared_ptr<RigidBody>)> _collisionCallBack;
|
||||||
|
|
||||||
static bool _nextSimplex(Simplex& points, Point4D& direction);
|
static NextSimplex _nextSimplex(const Simplex& points);
|
||||||
static bool _line(Simplex& points, Point4D& direction);
|
static NextSimplex _lineCase(const Simplex& points);
|
||||||
static bool _triangle(Simplex& points, Point4D& direction);
|
static NextSimplex _triangleCase(const Simplex& points);
|
||||||
static bool _tetrahedron(Simplex& points, Point4D& direction);
|
static NextSimplex _tetrahedronCase(const Simplex& points);
|
||||||
|
|
||||||
static std::pair<std::vector<Point4D>, size_t> _getFaceNormals(const std::vector<Point4D>& polytope, const std::vector<size_t>& faces);
|
static std::pair<std::vector<std::shared_ptr<FaceNormal>>, size_t> _getFaceNormals(const std::vector<Vec3D>& polytope, const std::vector<size_t>& faces);
|
||||||
static void _addIfUniqueEdge(std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b);
|
static std::vector<std::pair<size_t, size_t>> _addIfUniqueEdge(const std::vector<std::pair<size_t, size_t>>& edges, const std::vector<size_t>& faces, size_t a, size_t b);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Point4D _velocity;
|
std::unique_ptr<Vec3D> _velocity = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
|
||||||
Point4D _acceleration;
|
std::unique_ptr<Vec3D> _acceleration = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
|
||||||
|
|
||||||
bool _collision = false;
|
bool _collision = false;
|
||||||
bool _isCollider = true;
|
bool _isCollider = true;
|
||||||
|
|
||||||
bool _inCollision = false;
|
bool _inCollision = false;
|
||||||
Point4D _collisionNormal;
|
std::shared_ptr<Vec3D> _collisionNormal = std::make_unique<Vec3D>(Vec3D{0, 0, 0});;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RigidBody() = default;
|
RigidBody() = default;
|
||||||
explicit RigidBody(const Mesh& mesh);
|
explicit RigidBody(const Mesh& mesh);
|
||||||
|
|
||||||
std::pair<bool, Simplex> checkGJKCollision(std::shared_ptr<RigidBody> obj);
|
[[nodiscard]] std::pair<bool, Simplex> checkGJKCollision(std::shared_ptr<RigidBody> obj);
|
||||||
CollisionPoint EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj);
|
[[nodiscard]] CollisionPoint EPA(const Simplex& simplex, std::shared_ptr<RigidBody> obj);
|
||||||
|
|
||||||
[[nodiscard]] Point4D collisionNormal() const { return _collisionNormal; }
|
[[nodiscard]] Vec3D collisionNormal() const { return *_collisionNormal; }
|
||||||
|
|
||||||
[[nodiscard]] bool isCollision() const { return _collision; }
|
[[nodiscard]] bool isCollision() const { return _collision; }
|
||||||
[[nodiscard]] bool inCollision() const {return _inCollision; }
|
[[nodiscard]] bool inCollision() const {return _inCollision; }
|
||||||
|
@ -64,12 +72,12 @@ public:
|
||||||
|
|
||||||
void updatePhysicsState();
|
void updatePhysicsState();
|
||||||
|
|
||||||
void setVelocity(const Point4D& velocity);
|
void setVelocity(const Vec3D& velocity);
|
||||||
void addVelocity(const Point4D& velocity);
|
void addVelocity(const Vec3D& velocity);
|
||||||
void setAcceleration(const Point4D& acceleration);
|
void setAcceleration(const Vec3D& acceleration);
|
||||||
|
|
||||||
[[nodiscard]] Point4D velocity() const { return _velocity; }
|
[[nodiscard]] Vec3D velocity() const { return *_velocity; }
|
||||||
[[nodiscard]] Point4D acceleration() const { return _acceleration; }
|
[[nodiscard]] Vec3D acceleration() const { return *_acceleration; }
|
||||||
|
|
||||||
[[nodiscard]] const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& collisionCallBack() const { return _collisionCallBack; }
|
[[nodiscard]] const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& collisionCallBack() const { return _collisionCallBack; }
|
||||||
void setCollisionCallBack(const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& f) { _collisionCallBack = f; }
|
void setCollisionCallBack(const std::function<void(const std::string&, std::shared_ptr<RigidBody>)>& f) { _collisionCallBack = f; }
|
||||||
|
|
|
@ -5,34 +5,45 @@
|
||||||
#ifndef ENGINE_SIMPLEX_H
|
#ifndef ENGINE_SIMPLEX_H
|
||||||
#define ENGINE_SIMPLEX_H
|
#define ENGINE_SIMPLEX_H
|
||||||
|
|
||||||
#include "../utils/Point4D.h"
|
#include "../Vec3D.h"
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
enum class SimplexType {
|
||||||
|
Zero,
|
||||||
|
Point,
|
||||||
|
Line,
|
||||||
|
Triangle,
|
||||||
|
Tetrahedron
|
||||||
|
};
|
||||||
|
|
||||||
struct Simplex {
|
struct Simplex {
|
||||||
private:
|
private:
|
||||||
std::array<Point4D, 4> m_points{};
|
std::deque<Vec3D> _points{};
|
||||||
unsigned m_size = 0;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Simplex() = default;
|
Simplex() = default;
|
||||||
|
|
||||||
Simplex& operator=(std::initializer_list<Point4D> list) {
|
Simplex(std::initializer_list<Vec3D> list) {
|
||||||
for (auto v = list.begin(); v != list.end(); v++) {
|
for (const auto & v : list) {
|
||||||
m_points[std::distance(list.begin(), v)] = *v;
|
_points.push_back(v);
|
||||||
|
if(_points.size() > 4)
|
||||||
|
_points.pop_front();
|
||||||
}
|
}
|
||||||
m_size = list.size();
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_front(const Point4D& point) {
|
void push_front(const Vec3D& point) {
|
||||||
m_points = { point, m_points[0], m_points[1], m_points[2] };
|
_points.push_front(point);
|
||||||
m_size = std::min(m_size + 1, 4u);
|
if(_points.size() > 4)
|
||||||
|
_points.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D& operator[](unsigned i) { return m_points[i]; }
|
Vec3D operator[](unsigned i) const { return _points[i]; }
|
||||||
[[nodiscard]] unsigned size() const { return m_size; }
|
[[nodiscard]] unsigned size() const { return _points.size(); }
|
||||||
|
|
||||||
[[nodiscard]] auto begin() const { return m_points.begin(); }
|
[[nodiscard]] auto begin() const { return _points.begin(); }
|
||||||
[[nodiscard]] auto end() const { return m_points.end() - (4 - m_size); }
|
[[nodiscard]] auto end() const { return _points.end(); }
|
||||||
|
|
||||||
|
[[nodiscard]] SimplexType type() const { return static_cast<SimplexType>(_points.size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //INC_3DZAVR_SIMPLEX_H
|
#endif //INC_3DZAVR_SIMPLEX_H
|
||||||
|
|
|
@ -9,14 +9,11 @@ void Solver::solveCollision(std::shared_ptr<RigidBody> obj1, std::shared_ptr<Rig
|
||||||
if(!collision.hasCollision)
|
if(!collision.hasCollision)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Point4D obj1_velocity_parallel = collision.normal * obj1->velocity().dot(collision.normal);
|
Vec3D obj1_velocity_parallel = collision.normal * obj1->velocity().dot(collision.normal);
|
||||||
|
Vec3D obj1_velocity_perpendicular = obj1->velocity() - obj1_velocity_parallel;
|
||||||
|
|
||||||
obj1_velocity_parallel = Point4D{obj1_velocity_parallel.x(), obj1_velocity_parallel.y(), obj1_velocity_parallel.z(), 0};
|
Vec3D obj2_velocity_parallel = collision.normal * obj2->velocity().dot(collision.normal);
|
||||||
|
Vec3D obj2_velocity_perpendicular = obj2->velocity() - obj2_velocity_parallel;
|
||||||
Point4D obj1_velocity_perpendicular = obj1->velocity() - obj1_velocity_parallel;
|
|
||||||
|
|
||||||
Point4D obj2_velocity_parallel = collision.normal * obj2->velocity().dot(collision.normal);
|
|
||||||
Point4D obj2_velocity_perpendicular = obj2->velocity() - obj2_velocity_parallel;
|
|
||||||
|
|
||||||
if(obj1->isCollision()) {
|
if(obj1->isCollision()) {
|
||||||
if(obj1->velocity().dot(collision.normal) > 0) {
|
if(obj1->velocity().dot(collision.normal) > 0) {
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Ak47::Ak47(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/ak47.obj", "obj/ak47_mat.txt", Point4D{3, 3, 3}, Point4D{-0.8, 1.3, 0.3}, Point4D{0, Consts::PI, 0}) {
|
Ak47::Ak47(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/ak47.obj", "obj/ak47_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
|
||||||
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/ak47.ogg"));
|
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/ak47.ogg"));
|
||||||
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
class Gold_Ak47 : public Weapon {
|
class Gold_Ak47 : public Weapon {
|
||||||
public:
|
public:
|
||||||
explicit Gold_Ak47(int ammo = 200, const std::string& weaponName = "gold_ak47") : Weapon(weaponName, "obj/ak47.obj", "obj/gold_ak47_mat.txt", Point4D{3, 3, 3}, Point4D{-0.8, 1.3, 0.3}, Point4D{0, Consts::PI, 0}) {
|
explicit Gold_Ak47(int ammo = 200, const std::string& weaponName = "gold_ak47") : Weapon(weaponName, "obj/ak47.obj", "obj/gold_ak47_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
|
||||||
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/ak47.ogg"));
|
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/ak47.ogg"));
|
||||||
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Gun::Gun(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/gun.obj", "obj/gun_mat.txt", Point4D{3, 3, 3}, Point4D{-0.8, 1.3, 0.3}, Point4D{0, Consts::PI, 0}) {
|
Gun::Gun(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/gun.obj", "obj/gun_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) {
|
||||||
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/gun.ogg"));
|
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/gun.ogg"));
|
||||||
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_gun.ogg"));
|
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_gun.ogg"));
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "../engine/ResourceManager.h"
|
#include "../engine/ResourceManager.h"
|
||||||
#include "Rifle.h"
|
#include "Rifle.h"
|
||||||
|
|
||||||
Rifle::Rifle(int ammo, const std::string &weaponName) : Weapon(weaponName, "obj/rifle.obj", "obj/rifle_mat.txt", Point4D{3, 3, 3}, Point4D{-1.2, 1, 0.3}, Point4D{0, Consts::PI, 0}) {
|
Rifle::Rifle(int ammo, const std::string &weaponName) : Weapon(weaponName, "obj/rifle.obj", "obj/rifle_mat.txt", Vec3D{3, 3, 3}, Vec3D{-1.2, 1, 0.3}, Vec3D{0, Consts::PI, 0}) {
|
||||||
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/shotgun.ogg"));
|
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/shotgun.ogg"));
|
||||||
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_ak47.ogg"));
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/shotgun.obj", "obj/shotgun_mat.txt", Point4D{3, 3, 3}, Point4D{-0.95, 1.3, -0.6}, Point4D{0, Consts::PI, 0}) {
|
Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, "obj/shotgun.obj", "obj/shotgun_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.95, 1.3, -0.6}, Vec3D{0, Consts::PI, 0}) {
|
||||||
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/shotgun.ogg"));
|
fireSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/shotgun.ogg"));
|
||||||
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_shotgun.ogg"));
|
reloadSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/reload_shotgun.ogg"));
|
||||||
|
|
||||||
|
@ -25,12 +25,12 @@ Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, "
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, double>
|
std::map<std::string, double>
|
||||||
Shotgun::processFire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& pos, const Point4D& direction) {
|
Shotgun::processFire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& pos, const Vec3D& direction) {
|
||||||
std::map<std::string, double> damagedPlayers;
|
std::map<std::string, double> damagedPlayers;
|
||||||
|
|
||||||
for(int i = 0; i < 15; i++) {
|
for(int i = 0; i < 15; i++) {
|
||||||
//generate random vector
|
//generate random vector
|
||||||
Point4D randV(10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX));
|
Vec3D randV(10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX));
|
||||||
|
|
||||||
// damage player
|
// damage player
|
||||||
auto rayCast = rayCastFunction(pos, pos + direction * 1000 + randV);
|
auto rayCast = rayCastFunction(pos, pos + direction * 1000 + randV);
|
||||||
|
@ -38,8 +38,8 @@ Shotgun::processFire(std::function<std::pair<Point4D, std::string>(const Point4D
|
||||||
damagedPlayers[rayCast.second] += _damage / (1.0 + (pos - rayCast.first).abs());
|
damagedPlayers[rayCast.second] += _damage / (1.0 + (pos - rayCast.first).abs());
|
||||||
}
|
}
|
||||||
|
|
||||||
Point4D to = rayCast.first.w() == -1 ? pos + direction * 1000 + randV: rayCast.first;
|
Vec3D to = rayCast.first == Vec3D(0) ? pos + direction * 1000 + randV: rayCast.first;
|
||||||
Point4D from = position() + triangles().back()[0];
|
Vec3D from = position() + Vec3D(triangles().back()[0]);
|
||||||
_addTraceCallBack(from, to);
|
_addTraceCallBack(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
class Shotgun : public Weapon {
|
class Shotgun : public Weapon {
|
||||||
public:
|
public:
|
||||||
explicit Shotgun(int ammo = 15, const std::string& weaponName = "shotgun");
|
explicit Shotgun(int ammo = 15, const std::string& weaponName = "shotgun");
|
||||||
std::map<std::string, double> processFire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& position, const Point4D& direction) override;
|
std::map<std::string, double> processFire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, const std::string& matFileName, const Point4D& scale, const Point4D& t, const Point4D& r) {
|
Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, const std::string& matFileName, const Vec3D& scale, const Vec3D& t, const Vec3D& r) {
|
||||||
_name = weaponName;
|
_name = weaponName;
|
||||||
|
|
||||||
loadObj(objFileName, matFileName, scale);
|
loadObj(objFileName, matFileName, scale);
|
||||||
|
@ -23,7 +23,7 @@ Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, co
|
||||||
noAmmoSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/no_ammo.ogg"));
|
noAmmoSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/weapons/no_ammo.ogg"));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, double> Weapon::fire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& position, const Point4D& direction) {
|
std::map<std::string, double> Weapon::fire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction) {
|
||||||
if(_clipAmmo == 0) {
|
if(_clipAmmo == 0) {
|
||||||
reload();
|
reload();
|
||||||
if(_clipAmmo == 0)
|
if(_clipAmmo == 0)
|
||||||
|
@ -58,11 +58,11 @@ void Weapon::reload() {
|
||||||
_lastReloadTime = Time::time();
|
_lastReloadTime = Time::time();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, double> Weapon::processFire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& pos, const Point4D& direction) {
|
std::map<std::string, double> Weapon::processFire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& pos, const Vec3D& direction) {
|
||||||
std::map<std::string, double> damagedPlayers;
|
std::map<std::string, double> damagedPlayers;
|
||||||
|
|
||||||
//generate random vector
|
//generate random vector
|
||||||
Point4D randV(10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX));
|
Vec3D randV(10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX), 10.0*_spreading*(1.0 - 2.0*(double)rand()/RAND_MAX));
|
||||||
|
|
||||||
// damage player
|
// damage player
|
||||||
auto rayCast = rayCastFunction(pos, pos + direction * 1000 + randV);
|
auto rayCast = rayCastFunction(pos, pos + direction * 1000 + randV);
|
||||||
|
@ -71,8 +71,8 @@ std::map<std::string, double> Weapon::processFire(std::function<std::pair<Point4
|
||||||
}
|
}
|
||||||
|
|
||||||
// add trace line
|
// add trace line
|
||||||
Point4D to = rayCast.first.w() == -1 ? pos + direction * 1000 + randV: rayCast.first;
|
Vec3D to = rayCast.first == Vec3D(0) ? pos + direction * 1000 + randV: rayCast.first;
|
||||||
Point4D from = position() + triangles().back()[0];
|
Vec3D from = position() + Vec3D(triangles().back()[0]);
|
||||||
_addTraceCallBack(from, to);
|
_addTraceCallBack(from, to);
|
||||||
|
|
||||||
return damagedPlayers;
|
return damagedPlayers;
|
||||||
|
|
|
@ -40,19 +40,19 @@ protected:
|
||||||
|
|
||||||
int fireTraces = 0;
|
int fireTraces = 0;
|
||||||
|
|
||||||
std::function<void(const Point4D&, const Point4D&)> _addTraceCallBack;
|
std::function<void(const Vec3D&, const Vec3D&)> _addTraceCallBack;
|
||||||
|
|
||||||
virtual std::map<std::string, double> processFire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& position, const Point4D& direction);
|
virtual std::map<std::string, double> processFire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Weapon(const std::string& weaponName, const std::string& objFileName, const std::string& matFileName, const Point4D& scale, const Point4D& translate, const Point4D& rotate);
|
Weapon(const std::string& weaponName, const std::string& objFileName, const std::string& matFileName, const Vec3D& scale, const Vec3D& translate, const Vec3D& rotate);
|
||||||
|
|
||||||
std::map<std::string, double> fire(std::function<std::pair<Point4D, std::string>(const Point4D&, const Point4D&)> rayCastFunction, const Point4D& position, const Point4D& direction);
|
std::map<std::string, double> fire(std::function<std::pair<Vec3D, std::string>(const Vec3D&, const Vec3D&)> rayCastFunction, const Vec3D& position, const Vec3D& direction);
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
[[nodiscard]] std::pair<double, double> balance() const{ return std::make_pair(_clipAmmo, _stockAmmo); }
|
[[nodiscard]] std::pair<double, double> balance() const{ return std::make_pair(_clipAmmo, _stockAmmo); }
|
||||||
|
|
||||||
void setAddTraceCallBack(std::function<void(Point4D, Point4D)> add) {
|
void setAddTraceCallBack(std::function<void(Vec3D, Vec3D)> add) {
|
||||||
_addTraceCallBack = std::move(add);
|
_addTraceCallBack = std::move(add);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue