separate engine repository from the shooter repository by using submodules
parent
e76fd54f07
commit
f77312a334
2
3dzavr
2
3dzavr
|
@ -1 +1 @@
|
||||||
Subproject commit c93a7123c1e76008ae7819041cdc7d51461e07c2
|
Subproject commit f80ebaf4522310a7560c19e6da2a3a8f36f2eb16
|
162
CMakeLists.txt
162
CMakeLists.txt
|
@ -29,87 +29,87 @@ add_executable(${CMAKE_PROJECT_NAME}
|
||||||
network/ShooterMsgType.h
|
network/ShooterMsgType.h
|
||||||
network/ShooterMsgType.cpp
|
network/ShooterMsgType.cpp
|
||||||
# 3d engine:
|
# 3d engine:
|
||||||
engine/Consts.h
|
3dzavr/engine/Consts.h
|
||||||
engine/math/Vec4D.h
|
3dzavr/engine/math/Vec4D.h
|
||||||
engine/math/Vec4D.cpp
|
3dzavr/engine/math/Vec4D.cpp
|
||||||
engine/math/Vec3D.cpp
|
3dzavr/engine/math/Vec3D.cpp
|
||||||
engine/math/Vec3D.h
|
3dzavr/engine/math/Vec3D.h
|
||||||
engine/math/Vec2D.cpp
|
3dzavr/engine/math/Vec2D.cpp
|
||||||
engine/math/Vec2D.h
|
3dzavr/engine/math/Vec2D.h
|
||||||
engine/math/Matrix4x4.h
|
3dzavr/engine/math/Matrix4x4.h
|
||||||
engine/math/Matrix4x4.cpp
|
3dzavr/engine/math/Matrix4x4.cpp
|
||||||
engine/Triangle.h
|
3dzavr/engine/Triangle.h
|
||||||
engine/Triangle.cpp
|
3dzavr/engine/Triangle.cpp
|
||||||
engine/math/Plane.h
|
3dzavr/engine/math/Plane.h
|
||||||
engine/math/Plane.cpp
|
3dzavr/engine/math/Plane.cpp
|
||||||
engine/Mesh.h
|
3dzavr/engine/Mesh.h
|
||||||
engine/Mesh.cpp
|
3dzavr/engine/Mesh.cpp
|
||||||
engine/utils/Log.h
|
3dzavr/engine/utils/Log.h
|
||||||
engine/utils/Log.cpp
|
3dzavr/engine/utils/Log.cpp
|
||||||
engine/utils/Time.h
|
3dzavr/engine/utils/Time.h
|
||||||
engine/utils/Time.cpp
|
3dzavr/engine/utils/Time.cpp
|
||||||
engine/utils/Timer.cpp
|
3dzavr/engine/utils/Timer.cpp
|
||||||
engine/utils/Timer.h
|
3dzavr/engine/utils/Timer.h
|
||||||
engine/utils/ResourceManager.h
|
3dzavr/engine/utils/ResourceManager.h
|
||||||
engine/utils/ResourceManager.cpp
|
3dzavr/engine/utils/ResourceManager.cpp
|
||||||
engine/World.h
|
3dzavr/engine/World.h
|
||||||
engine/World.cpp
|
3dzavr/engine/World.cpp
|
||||||
engine/Camera.h
|
3dzavr/engine/Camera.h
|
||||||
engine/Camera.cpp
|
3dzavr/engine/Camera.cpp
|
||||||
engine/io/Screen.h
|
3dzavr/engine/io/Screen.h
|
||||||
engine/io/Screen.cpp
|
3dzavr/engine/io/Screen.cpp
|
||||||
engine/Engine.h
|
3dzavr/engine/Engine.h
|
||||||
engine/Engine.cpp
|
3dzavr/engine/Engine.cpp
|
||||||
engine/io/Keyboard.cpp
|
3dzavr/engine/io/Keyboard.cpp
|
||||||
engine/io/Keyboard.h
|
3dzavr/engine/io/Keyboard.h
|
||||||
engine/io/Mouse.cpp
|
3dzavr/engine/io/Mouse.cpp
|
||||||
engine/io/Mouse.h
|
3dzavr/engine/io/Mouse.h
|
||||||
engine/io/SoundController.cpp
|
3dzavr/engine/io/SoundController.cpp
|
||||||
engine/io/SoundController.h
|
3dzavr/engine/io/SoundController.h
|
||||||
engine/utils/ObjectController.cpp
|
3dzavr/engine/utils/ObjectController.cpp
|
||||||
engine/utils/ObjectController.h
|
3dzavr/engine/utils/ObjectController.h
|
||||||
engine/animation/Animation.h
|
3dzavr/engine/animation/Animation.h
|
||||||
engine/animation/Timeline.cpp
|
3dzavr/engine/animation/Timeline.cpp
|
||||||
engine/animation/Timeline.h
|
3dzavr/engine/animation/Timeline.h
|
||||||
engine/animation/Interpolation.h
|
3dzavr/engine/animation/Interpolation.h
|
||||||
engine/animation/Animation.cpp
|
3dzavr/engine/animation/Animation.cpp
|
||||||
engine/animation/ATranslate.h
|
3dzavr/engine/animation/ATranslate.h
|
||||||
engine/animation/AScale.h
|
3dzavr/engine/animation/AScale.h
|
||||||
engine/animation/ARotate.h
|
3dzavr/engine/animation/ARotate.h
|
||||||
engine/animation/AWait.h
|
3dzavr/engine/animation/AWait.h
|
||||||
engine/animation/AFunction.h
|
3dzavr/engine/animation/AFunction.h
|
||||||
engine/animation/AAttractToPoint.h
|
3dzavr/engine/animation/AAttractToPoint.h
|
||||||
engine/animation/ARotateRelativePoint.h
|
3dzavr/engine/animation/ARotateRelativePoint.h
|
||||||
engine/animation/ARotateLeft.h
|
3dzavr/engine/animation/ARotateLeft.h
|
||||||
engine/animation/Interpolation.cpp
|
3dzavr/engine/animation/Interpolation.cpp
|
||||||
engine/animation/Animations.h
|
3dzavr/engine/animation/Animations.h
|
||||||
engine/animation/AShowCreation.h
|
3dzavr/engine/animation/AShowCreation.h
|
||||||
engine/animation/AShowUncreation.h
|
3dzavr/engine/animation/AShowUncreation.h
|
||||||
engine/animation/ARotateLeftUpLookAt.h
|
3dzavr/engine/animation/ARotateLeftUpLookAt.h
|
||||||
engine/animation/ADecompose.h
|
3dzavr/engine/animation/ADecompose.h
|
||||||
engine/physics/RigidBody.cpp
|
3dzavr/engine/physics/RigidBody.cpp
|
||||||
engine/physics/RigidBody.h
|
3dzavr/engine/physics/RigidBody.h
|
||||||
engine/physics/Simplex.h
|
3dzavr/engine/physics/Simplex.h
|
||||||
engine/physics/HitBox.cpp
|
3dzavr/engine/physics/HitBox.cpp
|
||||||
engine/physics/HitBox.h
|
3dzavr/engine/physics/HitBox.h
|
||||||
engine/Object.cpp
|
3dzavr/engine/Object.cpp
|
||||||
engine/Object.h
|
3dzavr/engine/Object.h
|
||||||
engine/gui/Button.cpp
|
3dzavr/engine/gui/Button.cpp
|
||||||
engine/gui/Button.h
|
3dzavr/engine/gui/Button.h
|
||||||
engine/gui/Window.cpp
|
3dzavr/engine/gui/Window.cpp
|
||||||
engine/gui/Window.h
|
3dzavr/engine/gui/Window.h
|
||||||
engine/network/ClientUDP.cpp
|
3dzavr/engine/network/ClientUDP.cpp
|
||||||
engine/network/ClientUDP.h
|
3dzavr/engine/network/ClientUDP.h
|
||||||
engine/network/MsgType.cpp
|
3dzavr/engine/network/MsgType.cpp
|
||||||
engine/network/MsgType.h
|
3dzavr/engine/network/MsgType.h
|
||||||
engine/network/ReliableMsg.cpp
|
3dzavr/engine/network/ReliableMsg.cpp
|
||||||
engine/network/ReliableMsg.h
|
3dzavr/engine/network/ReliableMsg.h
|
||||||
engine/network/ServerUDP.cpp
|
3dzavr/engine/network/ServerUDP.cpp
|
||||||
engine/network/ServerUDP.h
|
3dzavr/engine/network/ServerUDP.h
|
||||||
engine/network/UDPConnection.cpp
|
3dzavr/engine/network/UDPConnection.cpp
|
||||||
engine/network/UDPConnection.h
|
3dzavr/engine/network/UDPConnection.h
|
||||||
engine/network/UDPSocket.cpp
|
3dzavr/engine/network/UDPSocket.cpp
|
||||||
engine/network/UDPSocket.h
|
3dzavr/engine/network/UDPSocket.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE OR UNIX)
|
if(APPLE OR UNIX)
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
#include "Shooter.h"
|
#include "Shooter.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "engine/animation/Animations.h"
|
#include "3dzavr/engine/animation/Animations.h"
|
||||||
#include "ShooterConsts.h"
|
#include "ShooterConsts.h"
|
||||||
#include "engine/io/SoundController.h"
|
#include "3dzavr/engine/io/SoundController.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
#ifndef SHOOTER_SHOOTER_H
|
#ifndef SHOOTER_SHOOTER_H
|
||||||
#define SHOOTER_SHOOTER_H
|
#define SHOOTER_SHOOTER_H
|
||||||
|
|
||||||
#include "engine/Engine.h"
|
#include "3dzavr/engine/Engine.h"
|
||||||
#include "player/Player.h"
|
#include "player/Player.h"
|
||||||
#include "player/PlayerController.h"
|
#include "player/PlayerController.h"
|
||||||
#include "player/PlayerController.h"
|
#include "player/PlayerController.h"
|
||||||
#include "engine/gui/Window.h"
|
#include "3dzavr/engine/gui/Window.h"
|
||||||
|
|
||||||
#include "network/ShooterClient.h"
|
#include "network/ShooterClient.h"
|
||||||
#include "network/ShooterServer.h"
|
#include "network/ShooterServer.h"
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "Camera.h"
|
|
||||||
#include "utils/Log.h"
|
|
||||||
#include "Consts.h"
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Triangle>> Camera::project(std::shared_ptr<Mesh> mesh) {
|
|
||||||
|
|
||||||
if (!_ready) {
|
|
||||||
Log::log("Camera::project(): cannot project _tris without camera initialization ( Camera::init() ) ");
|
|
||||||
return _triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mesh->isVisible()) {
|
|
||||||
return this->_triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Model transform matrix: translate _tris in the origin of body.
|
|
||||||
Matrix4x4 M = mesh->model();
|
|
||||||
Matrix4x4 V = invModel();
|
|
||||||
|
|
||||||
// We don't want to waste time re-allocating memory every time
|
|
||||||
std::vector<Triangle> clippedTriangles, tempBuffer;
|
|
||||||
|
|
||||||
for (auto &t : mesh->triangles()) {
|
|
||||||
|
|
||||||
Triangle MTriangle = t * M;
|
|
||||||
|
|
||||||
double dot = MTriangle.norm().dot((Vec3D(MTriangle[0]) - position()).normalized());
|
|
||||||
|
|
||||||
if (dot > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Triangle VMTriangle = MTriangle * V;
|
|
||||||
|
|
||||||
// It needs to be cleared because it's reused through iterations. Usually it doesn't free memory.
|
|
||||||
clippedTriangles.clear();
|
|
||||||
tempBuffer.clear();
|
|
||||||
|
|
||||||
// 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
|
|
||||||
clippedTriangles.emplace_back(VMTriangle);
|
|
||||||
for (auto &plane : _clipPlanes) {
|
|
||||||
while (!clippedTriangles.empty()) {
|
|
||||||
std::vector<Triangle> clipResult = plane.clip(clippedTriangles.back());
|
|
||||||
clippedTriangles.pop_back();
|
|
||||||
for (auto &i : clipResult) {
|
|
||||||
tempBuffer.emplace_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clippedTriangles.swap(tempBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &clipped : clippedTriangles) {
|
|
||||||
sf::Color color = clipped.color();
|
|
||||||
sf::Color ambientColor = sf::Color(static_cast<sf::Uint8>(color.r * (0.3 * std::abs(dot) + 0.7)),
|
|
||||||
static_cast<sf::Uint8>(color.g * (0.3 * std::abs(dot) + 0.7)),
|
|
||||||
static_cast<sf::Uint8>(color.b * (0.3 * std::abs(dot) + 0.7)),
|
|
||||||
static_cast<sf::Uint8>(color.a));
|
|
||||||
|
|
||||||
// Finally its time to project our clipped colored drawTriangle from 3D -> 2D
|
|
||||||
// and transform it's coordinate to screen space (in pixels):
|
|
||||||
Triangle clippedProjected = clipped * _SP;
|
|
||||||
|
|
||||||
Triangle clippedProjectedNormalized = Triangle(clippedProjected[0] / clippedProjected[0].w(),
|
|
||||||
clippedProjected[1] / clippedProjected[1].w(),
|
|
||||||
clippedProjected[2] / clippedProjected[2].w(),
|
|
||||||
ambientColor);
|
|
||||||
|
|
||||||
_triangles.emplace_back(std::make_shared<Triangle>(clippedProjectedNormalized));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->_triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::init(int width, int height, double fov, double ZNear, double ZFar) {
|
|
||||||
// We need to init camera only after creation or changing width, height, fov, ZNear or ZFar.
|
|
||||||
// Because here we calculate matrix that does not change during the motion of _objects or camera
|
|
||||||
_aspect = (double) width / (double) height;
|
|
||||||
Matrix4x4 P = Matrix4x4::Projection(fov, _aspect, ZNear, ZFar);
|
|
||||||
Matrix4x4 S = Matrix4x4::ScreenSpace(width, height);
|
|
||||||
|
|
||||||
_SP = S * P; // screen-space-projections matrix
|
|
||||||
|
|
||||||
// This is planes for clipping _tris.
|
|
||||||
// Motivation: we are not interest in _tris that we cannot see.
|
|
||||||
_clipPlanes.emplace_back(Plane(Vec3D{0, 0, 1}, Vec3D{0, 0, ZNear})); // near 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 thetta2 = atan(_aspect * tan(thetta1));
|
|
||||||
_clipPlanes.emplace_back(Plane(Vec3D{-cos(thetta2), 0, sin(thetta2)}, Vec3D{0, 0, 0})); // left plane
|
|
||||||
_clipPlanes.emplace_back(Plane(Vec3D{cos(thetta2), 0, sin(thetta2)}, Vec3D{0, 0, 0})); // right plane
|
|
||||||
_clipPlanes.emplace_back(Plane(Vec3D{0, cos(thetta1), sin(thetta1)}, Vec3D{0, 0, 0})); // down plane
|
|
||||||
_clipPlanes.emplace_back(Plane(Vec3D{0, -cos(thetta1), sin(thetta1)}, Vec3D{0, 0, 0})); // up plane
|
|
||||||
|
|
||||||
_ready = true;
|
|
||||||
Log::log("Camera::init(): camera successfully initialized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Triangle>> Camera::sorted() {
|
|
||||||
|
|
||||||
// Sort _tris from _back to front
|
|
||||||
// This is some replacement for Z-buffer
|
|
||||||
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_z2({(*t2)[0].z(), (*t2)[1].z(), (*t2)[2].z()});
|
|
||||||
|
|
||||||
std::sort(v_z1.begin(), v_z1.end());
|
|
||||||
std::sort(v_z2.begin(), v_z2.end());
|
|
||||||
|
|
||||||
double z1 = v_z1[0] + v_z1[1] + v_z1[2];
|
|
||||||
double z2 = v_z2[0] + v_z2[1] + v_z2[2];
|
|
||||||
|
|
||||||
return z1 > z2;
|
|
||||||
});
|
|
||||||
|
|
||||||
return _triangles;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Camera::clear() {
|
|
||||||
// Cleaning all _tris and recalculation of View matrix
|
|
||||||
_triangles.clear();
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_CAMERA_H
|
|
||||||
#define ENGINE_CAMERA_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <SFML/OpenGL.hpp>
|
|
||||||
|
|
||||||
#include "math/Plane.h"
|
|
||||||
#include "Mesh.h"
|
|
||||||
|
|
||||||
class Camera final : public Object {
|
|
||||||
private:
|
|
||||||
std::vector<std::shared_ptr<Triangle>> _triangles{};
|
|
||||||
std::vector<Plane> _clipPlanes{};
|
|
||||||
bool _ready = false;
|
|
||||||
double _aspect = 0;
|
|
||||||
|
|
||||||
Matrix4x4 _SP;
|
|
||||||
public:
|
|
||||||
Camera() : Object(ObjectNameTag("Camera")) {};
|
|
||||||
|
|
||||||
Camera(const Camera &camera) = delete;
|
|
||||||
|
|
||||||
void init(int width, int height, double fov = 90.0, double ZNear = 0.1, double ZFar = 5000.0);
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Triangle>> project(std::shared_ptr<Mesh> mesh);
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
[[nodiscard]] int buffSize() const { return _triangles.size(); }
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Triangle>> sorted();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_CAMERA_H
|
|
|
@ -1,60 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 07.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_CONSTS_H
|
|
||||||
#define SHOOTER_CONSTS_H
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
#include "math/Vec2D.h"
|
|
||||||
|
|
||||||
namespace Consts {
|
|
||||||
const int STANDARD_SCREEN_WIDTH = 1920;
|
|
||||||
const int STANDARD_SCREEN_HEIGHT = 1080;
|
|
||||||
const sf::Color BACKGROUND_COLOR = sf::Color(255, 255, 255);
|
|
||||||
const std::string PROJECT_NAME = "engine";
|
|
||||||
const bool USE_LOG_FILE = true;
|
|
||||||
const bool USE_OPEN_GL = true;
|
|
||||||
const bool SHOW_DEBUG_INFO = false;
|
|
||||||
const bool SHOW_FPS_COUNTER = true;
|
|
||||||
|
|
||||||
const double PI = 3.14159265358979323846264338327950288;
|
|
||||||
const double EPS = 0.000001;
|
|
||||||
|
|
||||||
const double EPA_EPS = 0.0001;
|
|
||||||
|
|
||||||
const double RAY_CAST_MAX_DISTANCE = 10000;
|
|
||||||
|
|
||||||
const std::string THIN_FONT = "engine/fonts/Roboto-Thin.ttf";
|
|
||||||
const std::string MEDIUM_FONT = "engine/fonts/Roboto-Medium.ttf";
|
|
||||||
|
|
||||||
const double LARGEST_TIME_STEP = 1.0 / 15.0;
|
|
||||||
const double TAP_DELAY = 0.2;
|
|
||||||
|
|
||||||
const Vec2D BEZIER[2] = {Vec2D{0.8, 0}, Vec2D{0.2, 1}};
|
|
||||||
|
|
||||||
const unsigned NETWORK_VERSION = 3U;
|
|
||||||
const int NETWORK_TIMEOUT = 5U;
|
|
||||||
const int NETWORK_WORLD_UPDATE_RATE = 30;
|
|
||||||
const double NETWORK_RELIABLE_RETRY_TIME = 1.0 / 20;
|
|
||||||
const uint16_t NETWORK_MAX_CLIENTS = 64;
|
|
||||||
|
|
||||||
const sf::Color WHITE_COLORS[] = {
|
|
||||||
sf::Color(137, 135, 222), // blue
|
|
||||||
sf::Color(195, 155, 209), // pink
|
|
||||||
sf::Color(201, 137, 137), // red
|
|
||||||
sf::Color(116, 204, 135), // green
|
|
||||||
sf::Color(201, 171, 137), // orange
|
|
||||||
};
|
|
||||||
|
|
||||||
const sf::Color DARK_COLORS[] = {
|
|
||||||
sf::Color(16, 18, 69), // blue
|
|
||||||
sf::Color(77, 0, 62), // pink
|
|
||||||
sf::Color(99, 20, 20), // red
|
|
||||||
sf::Color(12, 46, 9), // green
|
|
||||||
sf::Color(97, 70, 51), // orange
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif //SHOOTER_CONSTS_H
|
|
|
@ -1,197 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "Engine.h"
|
|
||||||
#include "utils/Time.h"
|
|
||||||
#include "utils/ResourceManager.h"
|
|
||||||
#include "animation/Timeline.h"
|
|
||||||
#include "io/SoundController.h"
|
|
||||||
|
|
||||||
Engine::Engine() {
|
|
||||||
Time::init();
|
|
||||||
Timeline::init();
|
|
||||||
ResourceManager::init();
|
|
||||||
SoundController::init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::create(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background,
|
|
||||||
sf::Uint32 style) {
|
|
||||||
_name = name;
|
|
||||||
screen->open(screenWidth, screenHeight, name, verticalSync, background, style);
|
|
||||||
|
|
||||||
Log::log("Engine::create(): started engine (" + std::to_string(screenWidth) + "x" + std::to_string(screenHeight) +
|
|
||||||
") with title '" + name + "'.");
|
|
||||||
Time::update();
|
|
||||||
|
|
||||||
start();
|
|
||||||
camera->init(screenWidth, screenHeight);
|
|
||||||
|
|
||||||
while (screen->isOpen()) {
|
|
||||||
// 'd' in the beginning of the name means debug.
|
|
||||||
// While printing debug info we will take into account only timer names witch start with 'd '
|
|
||||||
Time::startTimer("d all");
|
|
||||||
|
|
||||||
screen->clear();
|
|
||||||
|
|
||||||
Time::update();
|
|
||||||
|
|
||||||
Time::startTimer("d game update");
|
|
||||||
update();
|
|
||||||
Time::stopTimer("d game update");
|
|
||||||
|
|
||||||
// sometimes we dont need to update physics world
|
|
||||||
// (for example in menu or while pause)
|
|
||||||
// hence we can set '_updateWorld' equal to false in setUpdateWorld(bool):
|
|
||||||
if (_updateWorld) {
|
|
||||||
|
|
||||||
Time::startTimer("d animations");
|
|
||||||
Timeline::update();
|
|
||||||
Time::stopTimer("d animations");
|
|
||||||
|
|
||||||
Time::startTimer("d collisions");
|
|
||||||
world->update();
|
|
||||||
Time::stopTimer("d collisions");
|
|
||||||
|
|
||||||
Time::startTimer("d projections");
|
|
||||||
if (_useOpenGL) {
|
|
||||||
GLfloat *view = camera->glInvModel();
|
|
||||||
screen->popGLStates();
|
|
||||||
screen->prepareToGlDrawMesh();
|
|
||||||
for (auto &it : *world) {
|
|
||||||
if (it.second->isVisible()) {
|
|
||||||
GLfloat *model = it.second->glModel();
|
|
||||||
GLfloat *geometry = it.second->glFloatArray();
|
|
||||||
screen->glDrawMesh(geometry, view, model, 3 * it.second->triangles().size());
|
|
||||||
delete[] model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
screen->pushGLStates();
|
|
||||||
delete[] view;
|
|
||||||
} else {
|
|
||||||
// clear triangles from previous frame
|
|
||||||
camera->clear();
|
|
||||||
// project triangles to the camera plane
|
|
||||||
for (auto &it : *world) {
|
|
||||||
camera->project(it.second);
|
|
||||||
}
|
|
||||||
// draw triangles on the screen
|
|
||||||
for (auto &t : camera->sorted()) {
|
|
||||||
screen->drawTriangle(*t);
|
|
||||||
}
|
|
||||||
|
|
||||||
_triPerSec = camera->buffSize() * Time::fps();
|
|
||||||
}
|
|
||||||
Time::stopTimer("d projections");
|
|
||||||
|
|
||||||
if (Consts::SHOW_FPS_COUNTER) {
|
|
||||||
screen->drawText(std::to_string(Time::fps()) + " fps",
|
|
||||||
Vec2D(static_cast<double>(screen->width()) - 100.0, 10.0), 25,
|
|
||||||
sf::Color(100, 100, 100));
|
|
||||||
}
|
|
||||||
printDebugInfo();
|
|
||||||
gui();
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->display();
|
|
||||||
|
|
||||||
Time::stopTimer("d all");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::exit() {
|
|
||||||
if (screen->isOpen()) {
|
|
||||||
screen->close();
|
|
||||||
}
|
|
||||||
SoundController::free();
|
|
||||||
ResourceManager::free();
|
|
||||||
Timeline::free();
|
|
||||||
Time::free();
|
|
||||||
|
|
||||||
Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + "x" +
|
|
||||||
std::to_string(screen->height()) + ") with title '" + screen->title() + "'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::printDebugInfo() const {
|
|
||||||
|
|
||||||
if (_showDebugInfo) {
|
|
||||||
// coordinates & fps:
|
|
||||||
|
|
||||||
std::string text = _name + "\n\n X: " +
|
|
||||||
std::to_string((camera->position().x())) + "\n Y: " +
|
|
||||||
std::to_string((camera->position().y())) + "\n Z: " +
|
|
||||||
std::to_string((camera->position().z())) + "\n RY:" +
|
|
||||||
std::to_string(camera->angle().y()/Consts::PI) + "PI\n RL: " +
|
|
||||||
std::to_string(camera->angleLeftUpLookAt().x()/Consts::PI) + "PI\n\n" +
|
|
||||||
std::to_string(screen->width()) + "x" +
|
|
||||||
std::to_string(screen->height()) + "\t" +
|
|
||||||
std::to_string(Time::fps()) + " fps";
|
|
||||||
|
|
||||||
if (_useOpenGL) {
|
|
||||||
text += "\n Using OpenGL acceleration";
|
|
||||||
} else {
|
|
||||||
text += "\n" + std::to_string(_triPerSec) + " tris/s";
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Text t;
|
|
||||||
|
|
||||||
t.setFont(*ResourceManager::loadFont(Consts::THIN_FONT));
|
|
||||||
t.setString(text);
|
|
||||||
t.setCharacterSize(30);
|
|
||||||
t.setFillColor(sf::Color::Black);
|
|
||||||
t.setPosition(static_cast<float>(screen->width()) - 400.0f, 10.0f);
|
|
||||||
|
|
||||||
screen->drawText(t);
|
|
||||||
|
|
||||||
// timers:
|
|
||||||
int timerWidth = screen->width() - 100;
|
|
||||||
float xPos = 50;
|
|
||||||
float yPos = 300;
|
|
||||||
int height = 50;
|
|
||||||
|
|
||||||
double totalTime = Time::elapsedTimerSeconds("d all");
|
|
||||||
double timeSum = 0;
|
|
||||||
int i = 0;
|
|
||||||
for (auto &[timerName, timer] : Time::timers()) {
|
|
||||||
int width = timerWidth * timer.elapsedSeconds() / totalTime;
|
|
||||||
|
|
||||||
if (timerName == "d all" || timerName[0] != 'd') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
screen->drawTetragon(Vec2D{xPos, yPos + height * i},
|
|
||||||
Vec2D{xPos + width, yPos + height * i},
|
|
||||||
Vec2D{xPos + width, yPos + height + height * i},
|
|
||||||
Vec2D{xPos, yPos + height + height * i},
|
|
||||||
{static_cast<sf::Uint8>(255.0 * static_cast<double>(width) / timerWidth),
|
|
||||||
static_cast<sf::Uint8>(255.0 * (1.0 - static_cast<double>(width) / timerWidth)),
|
|
||||||
0, 100});
|
|
||||||
|
|
||||||
screen->drawText(
|
|
||||||
timerName.substr(2, timerName.size()) + ":\t" + std::to_string(timer.elapsedMilliseconds()) + " ms \t (" +
|
|
||||||
std::to_string((int) (100 * timer.elapsedSeconds() / totalTime)) + "%)",
|
|
||||||
Vec2D{xPos + 10, yPos + height * i + 5}, 30,
|
|
||||||
sf::Color(0, 0, 0, 150));
|
|
||||||
|
|
||||||
i++;
|
|
||||||
timeSum += timer.elapsedSeconds();
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = timerWidth * (totalTime - timeSum) / totalTime;
|
|
||||||
screen->drawTetragon(Vec2D{xPos, yPos + height * i},
|
|
||||||
Vec2D{xPos + width, yPos + height * i},
|
|
||||||
Vec2D{xPos + width, yPos + height + height * i},
|
|
||||||
Vec2D{xPos, yPos + height + height * i},
|
|
||||||
{static_cast<sf::Uint8>(255.0 * static_cast<double>(width) / timerWidth),
|
|
||||||
static_cast<sf::Uint8>(255.0 * (1.0 - static_cast<double>(width) / timerWidth)),
|
|
||||||
0, 100});
|
|
||||||
|
|
||||||
screen->drawText("other:\t" + std::to_string(1000*(totalTime - timeSum)) + " ms \t (" +
|
|
||||||
std::to_string((int) (100 * (totalTime - timeSum) / totalTime)) + "%)",
|
|
||||||
Vec2D{xPos + 10, yPos + height * i + 5}, 30,
|
|
||||||
sf::Color(0, 0, 0, 150));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ENGINE_H
|
|
||||||
#define ENGINE_ENGINE_H
|
|
||||||
|
|
||||||
#include "io/Screen.h"
|
|
||||||
#include "io/Keyboard.h"
|
|
||||||
#include "io/Mouse.h"
|
|
||||||
#include "World.h"
|
|
||||||
#include "Camera.h"
|
|
||||||
#include "utils/Log.h"
|
|
||||||
|
|
||||||
class Engine {
|
|
||||||
private:
|
|
||||||
std::string _name;
|
|
||||||
|
|
||||||
int _triPerSec = 0;
|
|
||||||
bool _updateWorld = true;
|
|
||||||
bool _showDebugInfo = Consts::SHOW_DEBUG_INFO;
|
|
||||||
bool _useOpenGL = Consts::USE_OPEN_GL;
|
|
||||||
|
|
||||||
void printDebugInfo() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const std::shared_ptr<Screen> screen = std::make_shared<Screen>();
|
|
||||||
const std::shared_ptr<Keyboard> keyboard = std::make_shared<Keyboard>();
|
|
||||||
const std::shared_ptr<Mouse> mouse = std::make_shared<Mouse>(screen);
|
|
||||||
|
|
||||||
const std::shared_ptr<World> world = std::make_shared<World>();
|
|
||||||
const std::shared_ptr<Camera> camera = std::make_shared<Camera>();
|
|
||||||
|
|
||||||
virtual void start() {};
|
|
||||||
|
|
||||||
virtual void update() {};
|
|
||||||
|
|
||||||
[[nodiscard]] bool showDebugInfo() const { return _showDebugInfo; }
|
|
||||||
void setDebugInfo(bool value) { _showDebugInfo = value; }
|
|
||||||
|
|
||||||
void setUpdateWorld(bool value) { _updateWorld = value; }
|
|
||||||
|
|
||||||
void setGlEnable(bool value) { _useOpenGL = value; }
|
|
||||||
[[nodiscard]] bool glEnable() const { return _useOpenGL; }
|
|
||||||
|
|
||||||
virtual void gui() {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Engine();
|
|
||||||
|
|
||||||
virtual ~Engine() = default;
|
|
||||||
|
|
||||||
void create(int screenWidth = Consts::STANDARD_SCREEN_WIDTH, int screenHeight = Consts::STANDARD_SCREEN_HEIGHT,
|
|
||||||
const std::string &name = Consts::PROJECT_NAME, bool verticalSync = true,
|
|
||||||
sf::Color background = Consts::BACKGROUND_COLOR, sf::Uint32 style = sf::Style::Default);
|
|
||||||
|
|
||||||
void exit();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_TDZAVR_H
|
|
223
engine/Mesh.cpp
223
engine/Mesh.cpp
|
@ -1,223 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Mesh.h"
|
|
||||||
#include "utils/ResourceManager.h"
|
|
||||||
#include "io/Screen.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
Mesh &Mesh::operator*=(const Matrix4x4 &matrix4X4) {
|
|
||||||
std::vector<Triangle> newTriangles;
|
|
||||||
newTriangles.reserve(_tris.size());
|
|
||||||
for (auto &t : _tris) {
|
|
||||||
newTriangles.emplace_back(t * matrix4X4);
|
|
||||||
}
|
|
||||||
setTriangles(std::move(newTriangles));
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mesh::loadObj(const std::string &filename, const Vec3D &scale) {
|
|
||||||
_tris.clear();
|
|
||||||
auto objects = ResourceManager::loadObjects(filename);
|
|
||||||
for (auto &obj : objects) {
|
|
||||||
for (auto &tri : obj->triangles()) {
|
|
||||||
_tris.push_back(tri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->scale(scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh::Mesh(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scale) : Object(std::move(nameTag)) {
|
|
||||||
loadObj(filename, scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh::Mesh(ObjectNameTag nameTag, const vector<Triangle> &tries) : Object(std::move(nameTag)), _tris(tries) {}
|
|
||||||
|
|
||||||
void Mesh::setColor(const sf::Color &c) {
|
|
||||||
_color = c;
|
|
||||||
|
|
||||||
for (auto &t : _tris) {
|
|
||||||
t.setColor(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
// because we change the color of mesh we should update geometry with a new color
|
|
||||||
glFreeFloatArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh
|
|
||||||
Mesh::LineTo(ObjectNameTag nameTag, const Vec3D &from, const Vec3D &to, double line_width, const sf::Color &color) {
|
|
||||||
|
|
||||||
Mesh line(std::move(nameTag));
|
|
||||||
|
|
||||||
Vec3D v1 = (to - from).normalized();
|
|
||||||
Vec3D v2 = from.cross(from + Vec3D{1, 0, 0}).normalized();
|
|
||||||
Vec3D v3 = v1.cross(v2).normalized();
|
|
||||||
|
|
||||||
// from plane
|
|
||||||
Vec4D p1 = (- v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p2 = (- v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p3 = ( v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p4 = ( v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
// to plane
|
|
||||||
Vec4D p5 = (to - from - v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p6 = (to - from - v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p7 = (to - from + v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p8 = (to - from + v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
|
|
||||||
|
|
||||||
line._tris = std::move(std::vector<Triangle>{
|
|
||||||
{p2, p4, p1},
|
|
||||||
{p2, p3, p4},
|
|
||||||
{p1, p6, p2},
|
|
||||||
{p1, p5, p6},
|
|
||||||
{p2, p6, p7},
|
|
||||||
{p2, p7, p3},
|
|
||||||
{p6, p5, p8},
|
|
||||||
{p6, p8, p7},
|
|
||||||
{p4, p3, p7},
|
|
||||||
{p4, p7, p8},
|
|
||||||
{p1, p8, p5},
|
|
||||||
{p1, p4, p8}
|
|
||||||
});
|
|
||||||
line.setColor(color);
|
|
||||||
line.translateToPoint(from);
|
|
||||||
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Mesh Mesh::ArrowTo(ObjectNameTag nameTag, const Vec3D &from, const Vec3D &to, double line_width, sf::Color color) {
|
|
||||||
|
|
||||||
Mesh arrow(std::move(nameTag));
|
|
||||||
|
|
||||||
Vec3D v1 = (to - from).normalized();
|
|
||||||
Vec3D v2 = from.cross(from + Vec3D{1, 0, 0}).normalized();
|
|
||||||
Vec3D v3 = v1.cross(v2).normalized();
|
|
||||||
|
|
||||||
Vec3D to_line = to - v1*0.4;
|
|
||||||
|
|
||||||
// from plane
|
|
||||||
Vec4D p1 = (- v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p2 = (- v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p3 = ( v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p4 = ( v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
// to plane
|
|
||||||
Vec4D p5 = (to_line - from - v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p6 = (to_line - from - v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p7 = (to_line - from + v2 * line_width / 2.0 + v3 * line_width / 2.0).makePoint4D();
|
|
||||||
Vec4D p8 = (to_line - from + v2 * line_width / 2.0 - v3 * line_width / 2.0).makePoint4D();
|
|
||||||
|
|
||||||
// arrow
|
|
||||||
Vec4D p9 = (to_line - from - v2 * line_width*2 - v3 * line_width*2).makePoint4D();
|
|
||||||
Vec4D p10 = (to_line - from - v2 * line_width*2 + v3 * line_width*2).makePoint4D();
|
|
||||||
Vec4D p11 = (to_line - from + v2 * line_width*2 + v3 * line_width*2).makePoint4D();
|
|
||||||
Vec4D p12 = (to_line - from + v2 * line_width*2 - v3 * line_width*2).makePoint4D();
|
|
||||||
|
|
||||||
Vec4D p13 = (to - from).makePoint4D();
|
|
||||||
|
|
||||||
arrow._tris = std::move(std::vector<Triangle>{
|
|
||||||
{p2, p4, p1},
|
|
||||||
{p2, p3, p4},
|
|
||||||
{p1, p6, p2},
|
|
||||||
{p1, p5, p6},
|
|
||||||
{p2, p6, p7},
|
|
||||||
{p2, p7, p3},
|
|
||||||
{p6, p5, p8},
|
|
||||||
{p6, p8, p7},
|
|
||||||
{p4, p3, p7},
|
|
||||||
{p4, p7, p8},
|
|
||||||
{p1, p8, p5},
|
|
||||||
{p1, p4, p8},
|
|
||||||
|
|
||||||
{ p9, p10, p13 },
|
|
||||||
{ p10, p11, p13 },
|
|
||||||
{ p11, p12, p13 },
|
|
||||||
{ p12, p9, p13 },
|
|
||||||
});
|
|
||||||
arrow.setColor(color);
|
|
||||||
arrow.translateToPoint(from);
|
|
||||||
|
|
||||||
return arrow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mesh::setOpacity(double t) {
|
|
||||||
setColor(sf::Color(_color.r, _color.g, _color.b, t*255));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mesh::setTriangles(vector<Triangle>&& t) {
|
|
||||||
_tris = std::move(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh::~Mesh() {
|
|
||||||
delete[] _geometry;
|
|
||||||
_geometry = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mesh::glFreeFloatArray() {
|
|
||||||
delete[] _geometry;
|
|
||||||
_geometry = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLfloat *Mesh::glFloatArray() const {
|
|
||||||
if(_geometry != nullptr) {
|
|
||||||
return _geometry;
|
|
||||||
}
|
|
||||||
_geometry = new GLfloat[7 * 3 * _tris.size()];
|
|
||||||
|
|
||||||
for (size_t i = 0; i < _tris.size(); i++) {
|
|
||||||
|
|
||||||
unsigned stride = 21 * i;
|
|
||||||
|
|
||||||
Triangle triangle = _tris[i];
|
|
||||||
Vec3D norm = (model()*triangle.norm()).normalized();
|
|
||||||
float dot = static_cast<float>(norm.dot(Vec3D(0, 1, 2).normalized()));
|
|
||||||
|
|
||||||
for (int k = 0; k < 3; k++) {
|
|
||||||
sf::Color color = triangle.color();
|
|
||||||
GLfloat ambientColor[4] = {
|
|
||||||
static_cast<float>(color.r) * (0.3f * std::fabs(dot) + 0.7f) / 255.0f,
|
|
||||||
static_cast<float>(color.g) * (0.3f * std::fabs(dot) + 0.7f) / 255.0f,
|
|
||||||
static_cast<float>(color.b) * (0.3f * std::fabs(dot) + 0.7f) / 255.0f,
|
|
||||||
static_cast<float>(color.a) / 255.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
_geometry[stride + 7 * k + 0] = static_cast<GLfloat>(triangle[k].x());
|
|
||||||
_geometry[stride + 7 * k + 1] = static_cast<GLfloat>(triangle[k].y());
|
|
||||||
_geometry[stride + 7 * k + 2] = static_cast<GLfloat>(triangle[k].z());
|
|
||||||
|
|
||||||
_geometry[stride + 7 * k + 3] = ambientColor[0];
|
|
||||||
_geometry[stride + 7 * k + 4] = ambientColor[1];
|
|
||||||
_geometry[stride + 7 * k + 5] = ambientColor[2];
|
|
||||||
_geometry[stride + 7 * k + 6] = ambientColor[3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mesh Mesh::Cube(ObjectNameTag tag, double size, sf::Color color) {
|
|
||||||
Mesh cube(std::move(tag));
|
|
||||||
|
|
||||||
cube._tris = {
|
|
||||||
{ Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 0.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 0.0, 1.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 1.0, 1.0} },
|
|
||||||
{ Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{0.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0} },
|
|
||||||
{ Vec4D{0.0, 1.0, 0.0, 1.0}, Vec4D{1.0, 1.0, 1.0, 1.0}, Vec4D{1.0, 1.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0} },
|
|
||||||
{ Vec4D{1.0, 0.0, 1.0, 1.0}, Vec4D{0.0, 0.0, 0.0, 1.0}, Vec4D{1.0, 0.0, 0.0, 1.0} },
|
|
||||||
};
|
|
||||||
cube.setColor(color);
|
|
||||||
|
|
||||||
return cube *= Matrix4x4::Scale(Vec3D(size, size, size))*Matrix4x4::Translation(Vec3D(-0.5, -0.5, -0.5));
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_MESH_H
|
|
||||||
#define ENGINE_MESH_H
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
#include "Triangle.h"
|
|
||||||
#include "Object.h"
|
|
||||||
|
|
||||||
class Mesh : public Object {
|
|
||||||
private:
|
|
||||||
std::vector<Triangle> _tris;
|
|
||||||
sf::Color _color = sf::Color(255, 245, 194);
|
|
||||||
bool _visible = true;
|
|
||||||
|
|
||||||
Mesh &operator*=(const Matrix4x4 &matrix4X4);
|
|
||||||
|
|
||||||
// OpenGL
|
|
||||||
mutable GLfloat* _geometry = nullptr;
|
|
||||||
public:
|
|
||||||
explicit Mesh(ObjectNameTag nameTag) : Object(std::move(nameTag)) {};
|
|
||||||
|
|
||||||
Mesh &operator=(const Mesh &mesh) = delete;
|
|
||||||
|
|
||||||
Mesh(const Mesh &mesh) = default;
|
|
||||||
|
|
||||||
explicit Mesh(ObjectNameTag nameTag, const std::vector<Triangle> &tries);
|
|
||||||
|
|
||||||
explicit Mesh(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scale = Vec3D{1, 1, 1});
|
|
||||||
|
|
||||||
void loadObj(const std::string &filename, const Vec3D &scale = Vec3D{1, 1, 1});
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Triangle> const &triangles() const { return _tris; }
|
|
||||||
|
|
||||||
void setTriangles(std::vector<Triangle>&& t);
|
|
||||||
|
|
||||||
[[nodiscard]] size_t size() const { return _tris.size() * 3; }
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Color color() const { return _color; }
|
|
||||||
|
|
||||||
void setColor(const sf::Color &c);
|
|
||||||
|
|
||||||
void setOpacity(double t);
|
|
||||||
|
|
||||||
void setVisible(bool visibility) { _visible = visibility; }
|
|
||||||
|
|
||||||
[[nodiscard]] bool isVisible() const { return _visible; }
|
|
||||||
|
|
||||||
~Mesh() override;
|
|
||||||
|
|
||||||
Mesh static Cube(ObjectNameTag tag, double size = 1.0, sf::Color color = sf::Color(0,0,0));
|
|
||||||
|
|
||||||
Mesh static LineTo(ObjectNameTag nameTag, const Vec3D &from, const Vec3D &to, double line_width = 0.1,
|
|
||||||
const sf::Color &color = {150, 150, 150, 100});
|
|
||||||
|
|
||||||
Mesh static ArrowTo(ObjectNameTag nameTag, const Vec3D& from, const Vec3D& to, double line_width = 0.1, sf::Color color = {150, 150, 150, 255});
|
|
||||||
|
|
||||||
// OpenGL functions
|
|
||||||
GLfloat *glFloatArray() const;
|
|
||||||
void glFreeFloatArray();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_MESH_H
|
|
|
@ -1,211 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 15.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "Object.h"
|
|
||||||
#include "math/Matrix4x4.h"
|
|
||||||
|
|
||||||
bool ObjectNameTag::contains(const ObjectNameTag &nameTag) const {
|
|
||||||
if(_name.find(nameTag.str()) != std::string::npos) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::transform(const Matrix4x4 &t) {
|
|
||||||
_transformMatrix = t * _transformMatrix;
|
|
||||||
|
|
||||||
for (auto &[attachedName, attachedObject] : _attachedObjects) {
|
|
||||||
if (!attachedObject.expired()) {
|
|
||||||
attachedObject.lock()->transformRelativePoint(position(), t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::transformRelativePoint(const Vec3D &point, const Matrix4x4 &transform) {
|
|
||||||
|
|
||||||
// translate object in new coordinate system (connected with point)
|
|
||||||
_transformMatrix = Matrix4x4::Translation(position() - point) * _transformMatrix;
|
|
||||||
// transform object in the new coordinate system
|
|
||||||
_transformMatrix = transform * _transformMatrix;
|
|
||||||
// translate object back in self connected coordinate system
|
|
||||||
_position = _transformMatrix.w() + point;
|
|
||||||
_transformMatrix = Matrix4x4::Translation(-_transformMatrix.w()) * _transformMatrix;
|
|
||||||
|
|
||||||
for (auto &[attachedName, attachedObject] : _attachedObjects) {
|
|
||||||
if (!attachedObject.expired()) {
|
|
||||||
attachedObject.lock()->transformRelativePoint(point, transform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::translate(const Vec3D &dv) {
|
|
||||||
|
|
||||||
_position = _position + dv;
|
|
||||||
|
|
||||||
for (auto &[attachedName, attachedObject] : _attachedObjects) {
|
|
||||||
if (!attachedObject.expired()) {
|
|
||||||
attachedObject.lock()->translate(dv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::scale(const Vec3D &s) {
|
|
||||||
transform(Matrix4x4::Scale(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotate(const Vec3D &r) {
|
|
||||||
_angle = _angle + r;
|
|
||||||
|
|
||||||
Matrix4x4 rotationMatrix = Matrix4x4::RotationX(r.x()) * Matrix4x4::RotationY(r.y()) * Matrix4x4::RotationZ(r.z());
|
|
||||||
transform(rotationMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotate(const Vec3D &v, double rv) {
|
|
||||||
transform(Matrix4x4::Rotation(v, rv));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &r) {
|
|
||||||
_angle = _angle + r;
|
|
||||||
|
|
||||||
transformRelativePoint(s, Matrix4x4::Rotation(r));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateRelativePoint(const Vec3D &s, const Vec3D &v, double r) {
|
|
||||||
transformRelativePoint(s, Matrix4x4::Rotation(v, r));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateLeft(double rl) {
|
|
||||||
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x() + rl,
|
|
||||||
_angleLeftUpLookAt.y(),
|
|
||||||
_angleLeftUpLookAt.z()};
|
|
||||||
|
|
||||||
rotate(left(), rl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateUp(double ru) {
|
|
||||||
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x(),
|
|
||||||
_angleLeftUpLookAt.y() + ru,
|
|
||||||
_angleLeftUpLookAt.z()};
|
|
||||||
|
|
||||||
rotate(up(), ru);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateLookAt(double rlAt) {
|
|
||||||
_angleLeftUpLookAt = Vec3D{_angleLeftUpLookAt.x(),
|
|
||||||
_angleLeftUpLookAt.y(),
|
|
||||||
_angleLeftUpLookAt.z() + rlAt};
|
|
||||||
rotate(lookAt(), rlAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::translateToPoint(const Vec3D &point) {
|
|
||||||
translate(point - position());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::attractToPoint(const Vec3D &point, double value) {
|
|
||||||
Vec3D v = (point - position()).normalized();
|
|
||||||
translate(v*value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::rotateToAngle(const Vec3D &v) {
|
|
||||||
rotate(v - _angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Object> Object::attached(const ObjectNameTag &tag) {
|
|
||||||
if (_attachedObjects.count(tag) == 0 || _attachedObjects.find(tag)->second.expired()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return _attachedObjects.find(tag)->second.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Object::checkIfAttached(Object *obj) {
|
|
||||||
for (const auto&[nameTag, attachedObject] : _attachedObjects) {
|
|
||||||
if (obj == attachedObject.lock().get() || attachedObject.lock()->checkIfAttached(obj)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::attach(std::shared_ptr<Object> object) {
|
|
||||||
if (this != object.get()) {
|
|
||||||
if (!object->checkIfAttached(this)) {
|
|
||||||
_attachedObjects.emplace(object->name(), object);
|
|
||||||
} else {
|
|
||||||
throw std::invalid_argument{"Object::attach: You tried to create infinite recursive call chains"};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::invalid_argument{"Object::attach: You cannot attach object to itself"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Object::unattach(const ObjectNameTag &tag) {
|
|
||||||
_attachedObjects.erase(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenGL function
|
|
||||||
GLfloat *Object::glInvModel() const {
|
|
||||||
auto *v = new GLfloat[4 * 4];
|
|
||||||
|
|
||||||
Vec3D _left = _transformMatrix.x();
|
|
||||||
Vec3D _up = _transformMatrix.y();
|
|
||||||
Vec3D _lookAt = _transformMatrix.z();
|
|
||||||
|
|
||||||
v[0] = -static_cast<GLfloat>(_left.x());
|
|
||||||
v[4] = -static_cast<GLfloat>(_left.y());
|
|
||||||
v[8] = -static_cast<GLfloat>(_left.z());
|
|
||||||
v[12] = static_cast<GLfloat>(position().dot(_left));
|
|
||||||
|
|
||||||
v[1] = static_cast<GLfloat>(_up.x());
|
|
||||||
v[5] = static_cast<GLfloat>(_up.y());
|
|
||||||
v[9] = static_cast<GLfloat>(_up.z());
|
|
||||||
v[13] = -static_cast<GLfloat>(position().dot(_up));
|
|
||||||
|
|
||||||
v[2] = -static_cast<GLfloat>(_lookAt.x());
|
|
||||||
v[6] = -static_cast<GLfloat>(_lookAt.y());
|
|
||||||
v[10] = -static_cast<GLfloat>(_lookAt.z());
|
|
||||||
v[14] = static_cast<GLfloat>(position().dot(_lookAt));
|
|
||||||
|
|
||||||
v[3] = static_cast<GLfloat>(0.0f);
|
|
||||||
v[7] = static_cast<GLfloat>(0.0f);
|
|
||||||
v[11] = static_cast<GLfloat>(0.0f);
|
|
||||||
v[15] = static_cast<GLfloat>(1.0f);
|
|
||||||
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLfloat *Object::glModel() const {
|
|
||||||
auto *m = new GLfloat[4 * 4];
|
|
||||||
|
|
||||||
Vec3D _left = _transformMatrix.x();
|
|
||||||
Vec3D _up = _transformMatrix.y();
|
|
||||||
Vec3D _lookAt = _transformMatrix.z();
|
|
||||||
|
|
||||||
m[0] = static_cast<GLfloat>(_left.x());
|
|
||||||
m[4] = static_cast<GLfloat>(_up.x());
|
|
||||||
m[8] = static_cast<GLfloat>(_lookAt.x());
|
|
||||||
m[12] = static_cast<GLfloat>(position().x());
|
|
||||||
|
|
||||||
m[1] = static_cast<GLfloat>(_left.y());
|
|
||||||
m[5] = static_cast<GLfloat>(_up.y());
|
|
||||||
m[9] = static_cast<GLfloat>(_lookAt.y());
|
|
||||||
m[13] = static_cast<GLfloat>(position().y());
|
|
||||||
|
|
||||||
m[2] = static_cast<GLfloat>(_left.z());
|
|
||||||
m[6] = static_cast<GLfloat>(_up.z());
|
|
||||||
m[10] = static_cast<GLfloat>(_lookAt.z());
|
|
||||||
m[14] = static_cast<GLfloat>(position().z());
|
|
||||||
|
|
||||||
m[3] = static_cast<GLfloat>(0.0f);
|
|
||||||
m[7] = static_cast<GLfloat>(0.0f);
|
|
||||||
m[11] = static_cast<GLfloat>(0.0f);
|
|
||||||
m[15] = static_cast<GLfloat>(1.0f);
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object::~Object() {
|
|
||||||
_attachedObjects.clear();
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 15.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_OBJECT_H
|
|
||||||
#define ENGINE_OBJECT_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "math/Vec3D.h"
|
|
||||||
#include "math/Matrix4x4.h"
|
|
||||||
#include <SFML/OpenGL.hpp>
|
|
||||||
|
|
||||||
class ObjectNameTag final {
|
|
||||||
private:
|
|
||||||
const std::string _name;
|
|
||||||
public:
|
|
||||||
explicit ObjectNameTag(std::string name = "") : _name(std::move(name)) {}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string str() const { return _name; }
|
|
||||||
|
|
||||||
bool operator==(const ObjectNameTag &tag) const { return _name == tag._name; }
|
|
||||||
bool operator!=(const ObjectNameTag &tag) const { return _name != tag._name; }
|
|
||||||
bool operator<(const ObjectNameTag &tag) const { return _name < tag._name; }
|
|
||||||
|
|
||||||
[[nodiscard]] bool contains(const ObjectNameTag& nameTag) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Object {
|
|
||||||
private:
|
|
||||||
bool checkIfAttached(Object *obj);
|
|
||||||
|
|
||||||
const ObjectNameTag _nameTag;
|
|
||||||
|
|
||||||
Matrix4x4 _transformMatrix = Matrix4x4::Identity();
|
|
||||||
Vec3D _position{0, 0, 0};
|
|
||||||
/*
|
|
||||||
* Take into account when you rotate body,
|
|
||||||
* you change '_angle' & '_angleLeftUpLookAt' only for this particular body,
|
|
||||||
* but not for attached objects! This way during rotation
|
|
||||||
* '_angle' & '_angleLeftUpLookAt' stays constant all attached objects.
|
|
||||||
*/
|
|
||||||
Vec3D _angle{0, 0, 0};
|
|
||||||
Vec3D _angleLeftUpLookAt{0, 0, 0};
|
|
||||||
|
|
||||||
std::map<ObjectNameTag, std::weak_ptr<Object>> _attachedObjects;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Object(ObjectNameTag nameTag) : _nameTag(std::move(nameTag)) {};
|
|
||||||
|
|
||||||
Object(const Object &object) : _nameTag(object._nameTag),
|
|
||||||
_transformMatrix(object._transformMatrix),
|
|
||||||
_position(object._position),
|
|
||||||
_angle(object._angle),
|
|
||||||
_angleLeftUpLookAt(object._angleLeftUpLookAt) {};
|
|
||||||
|
|
||||||
// TODO: implement rotations using quaternions (?)
|
|
||||||
void transform(const Matrix4x4 &t);
|
|
||||||
void transformRelativePoint(const Vec3D &point, const Matrix4x4 &transform);
|
|
||||||
void translate(const Vec3D &dv);
|
|
||||||
void translateToPoint(const Vec3D &point);
|
|
||||||
void attractToPoint(const Vec3D &point, double value);
|
|
||||||
void scale(const Vec3D &s);
|
|
||||||
void rotate(const Vec3D &r);
|
|
||||||
void rotate(const Vec3D &v, double rv);
|
|
||||||
void rotateToAngle(const Vec3D &v);
|
|
||||||
void rotateRelativePoint(const Vec3D &s, const Vec3D &r);
|
|
||||||
void rotateRelativePoint(const Vec3D &s, const Vec3D &v, double r);
|
|
||||||
void rotateLeft(double rl);
|
|
||||||
void rotateUp(double ru);
|
|
||||||
void rotateLookAt(double rlAt);
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D left() const { return _transformMatrix.x().normalized(); }
|
|
||||||
[[nodiscard]] Vec3D up() const { return _transformMatrix.y().normalized(); }
|
|
||||||
[[nodiscard]] Vec3D lookAt() const { return _transformMatrix.z().normalized(); }
|
|
||||||
[[nodiscard]] Vec3D position() const { return _position; }
|
|
||||||
[[nodiscard]] Vec3D angle() const { return _angle; }
|
|
||||||
[[nodiscard]] Vec3D angleLeftUpLookAt() const { return _angleLeftUpLookAt; }
|
|
||||||
|
|
||||||
void attach(std::shared_ptr<Object> object);
|
|
||||||
void unattach(const ObjectNameTag &tag);
|
|
||||||
std::shared_ptr<Object> attached(const ObjectNameTag &tag);
|
|
||||||
|
|
||||||
[[nodiscard]] ObjectNameTag name() const { return _nameTag; }
|
|
||||||
|
|
||||||
[[nodiscard]] Matrix4x4 model() const { return Matrix4x4::Translation(_position) * _transformMatrix; }
|
|
||||||
[[nodiscard]] Matrix4x4 invModel() const { return Matrix4x4::View(model()); }
|
|
||||||
|
|
||||||
// OpenGL function
|
|
||||||
[[nodiscard]] GLfloat *glModel() const;
|
|
||||||
[[nodiscard]] GLfloat *glInvModel() const;
|
|
||||||
|
|
||||||
virtual ~Object();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //MINECRAFT_3DZAVR_OBJECT_H
|
|
|
@ -1,52 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Triangle.h"
|
|
||||||
#include "Consts.h"
|
|
||||||
|
|
||||||
Triangle::Triangle(const Vec4D &p1, const Vec4D &p2, const Vec4D &p3, sf::Color color) : _color(color),
|
|
||||||
_points{p1, p2, p3} {
|
|
||||||
calculateNormal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Triangle::calculateNormal() {
|
|
||||||
Vec3D v1 = Vec3D(_points[1] - _points[0]);
|
|
||||||
Vec3D v2 = Vec3D(_points[2] - _points[0]);
|
|
||||||
Vec3D crossProduct = v1.cross(v2);
|
|
||||||
|
|
||||||
if (crossProduct.sqrAbs() > Consts::EPS) {
|
|
||||||
_normal = crossProduct.normalized();
|
|
||||||
} else {
|
|
||||||
_normal = Vec3D(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Triangle::Triangle(const Triangle &triangle) : _points{triangle._points[0], triangle._points[1], triangle._points[2]},
|
|
||||||
_color(triangle._color), _normal(triangle._normal) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Triangle Triangle::operator*(const Matrix4x4 &matrix4X4) const {
|
|
||||||
return Triangle(matrix4X4 * _points[0], matrix4X4 * _points[1], matrix4X4 * _points[2], _color);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Triangle::norm() const {
|
|
||||||
return _normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vec4D& Triangle::operator[](int i) const {
|
|
||||||
return _points[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Triangle::isPointInside(const Vec3D &point) const {
|
|
||||||
Vec3D triangleNorm = norm();
|
|
||||||
|
|
||||||
double dot1 = (point - Vec3D(_points[0])).cross(Vec3D(_points[1] - _points[0])).dot(triangleNorm);
|
|
||||||
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);
|
|
||||||
|
|
||||||
if ((dot1 >= 0 && dot2 >= 0 && dot3 >= 0) || (dot1 <= 0 && dot2 <= 0 && dot3 <= 0)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_TRIANGLE_H
|
|
||||||
#define ENGINE_TRIANGLE_H
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
#include "math/Vec4D.h"
|
|
||||||
#include "math/Vec3D.h"
|
|
||||||
#include "math/Matrix4x4.h"
|
|
||||||
|
|
||||||
class Triangle final {
|
|
||||||
private:
|
|
||||||
sf::Color _color;
|
|
||||||
Vec4D _points[3];
|
|
||||||
Vec3D _normal;
|
|
||||||
|
|
||||||
void calculateNormal();
|
|
||||||
public:
|
|
||||||
Triangle() = default;
|
|
||||||
|
|
||||||
Triangle(const Triangle &triangle);
|
|
||||||
|
|
||||||
Triangle(const Vec4D &p1, const Vec4D &p2, const Vec4D &p3, sf::Color color = {0, 0, 0});
|
|
||||||
|
|
||||||
Triangle &operator=(const Triangle &) = default;
|
|
||||||
|
|
||||||
[[nodiscard]] const Vec4D& operator[](int i) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D position() const { return Vec3D(_points[0] + _points[1] + _points[2])/3; }
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D norm() const;
|
|
||||||
|
|
||||||
// Operations with Matrix4x4
|
|
||||||
[[nodiscard]] Triangle operator*(const Matrix4x4 &matrix4X4) const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool isPointInside(const Vec3D &point) const;
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Color color() const { return _color; }
|
|
||||||
|
|
||||||
void setColor(sf::Color newColor) { _color = newColor; }
|
|
||||||
|
|
||||||
[[nodiscard]] double distance(const Vec3D &vec) const { return norm().dot(Vec3D(_points[0]) - vec); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_TRIANGLE_H
|
|
164
engine/World.cpp
164
engine/World.cpp
|
@ -1,164 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <sstream>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "World.h"
|
|
||||||
#include "utils/Log.h"
|
|
||||||
#include "math/Plane.h"
|
|
||||||
#include "utils/ResourceManager.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
std::shared_ptr<RigidBody> World::addBody(std::shared_ptr<RigidBody> body) {
|
|
||||||
_objects.emplace(body->name(), body);
|
|
||||||
Log::log("World::addBody(): inserted body '" + body->name().str() + "' with " +
|
|
||||||
std::to_string(_objects[body->name()]->triangles().size()) + " tris.");
|
|
||||||
return _objects[body->name()];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<RigidBody> World::loadBody(const ObjectNameTag &tag, const string &filename, const Vec3D &scale) {
|
|
||||||
_objects.emplace(tag, std::make_shared<RigidBody>(tag, filename, scale));
|
|
||||||
Log::log("World::loadBody(): inserted body from " + filename + " with title '" + tag.str() + "' with " +
|
|
||||||
std::to_string(_objects[tag]->triangles().size()) + " tris.");
|
|
||||||
return _objects[tag];
|
|
||||||
}
|
|
||||||
|
|
||||||
IntersectionInformation World::rayCast(const Vec3D &from, const Vec3D &to, const std::string &skipTags) {
|
|
||||||
|
|
||||||
// make vector of tags, that we are going to escape
|
|
||||||
vector<std::string> tagsToSkip;
|
|
||||||
stringstream s(skipTags);
|
|
||||||
std::string t;
|
|
||||||
while (s >> t) {
|
|
||||||
tagsToSkip.push_back(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool intersected = false;
|
|
||||||
Vec3D point{};
|
|
||||||
Triangle triangle;
|
|
||||||
std::string bodyName;
|
|
||||||
double minDistance = Consts::RAY_CAST_MAX_DISTANCE;
|
|
||||||
std::shared_ptr<RigidBody> intersectedBody = nullptr;
|
|
||||||
|
|
||||||
for (auto&[name, body] : _objects) {
|
|
||||||
|
|
||||||
bool escapeThisBody = false;
|
|
||||||
for (auto &escapeTag : tagsToSkip) {
|
|
||||||
if (name.contains(ObjectNameTag(escapeTag))) {
|
|
||||||
escapeThisBody = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (escapeThisBody) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 model = body->model();
|
|
||||||
// It is computationally more efficient not to transform all object's triangles from model to global
|
|
||||||
// coordinate system, but translate 'from' and 'to' vectors inside once and check triangles without performing
|
|
||||||
// many matrix multiplication.
|
|
||||||
Matrix4x4 invModel = body->invModel();
|
|
||||||
|
|
||||||
Vec3D v = (to - from).normalized();
|
|
||||||
Vec3D v_model = invModel*v;
|
|
||||||
Vec3D from_model = invModel*(from - body->position());
|
|
||||||
Vec3D to_model = invModel*(to - body->position());
|
|
||||||
|
|
||||||
|
|
||||||
for (auto &tri : body->triangles()) {
|
|
||||||
|
|
||||||
if(tri.norm().dot(v_model) > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto intersection = Plane(tri).intersection(from_model, to_model);
|
|
||||||
|
|
||||||
if (intersection.second > 0 && tri.isPointInside(intersection.first)) {
|
|
||||||
|
|
||||||
// When you change to model coordinate system you also will get distance scaled by invModel.
|
|
||||||
// Due-to this effect if you scale some object in x times you will get distance in x times smaller.
|
|
||||||
// That's why we need to perform distance calculation in the global coordinate system where metric
|
|
||||||
// is the same for all objects.
|
|
||||||
Triangle globalTriangle(model * tri[0], model * tri[1], model * tri[2], tri.color());
|
|
||||||
auto globalIntersection = Plane(globalTriangle).intersection(from, to);
|
|
||||||
double globalDistance = (globalIntersection.first - from).abs();
|
|
||||||
|
|
||||||
if(globalDistance < minDistance) {
|
|
||||||
minDistance = globalDistance;
|
|
||||||
point = globalIntersection.first;
|
|
||||||
triangle = globalTriangle;
|
|
||||||
bodyName = name.str();
|
|
||||||
intersected = true;
|
|
||||||
intersectedBody = body;
|
|
||||||
//Triangle triangleRED = Triangle(model * tri[0], model * tri[1], model * tri[2], sf::Color(255, 0, 0));
|
|
||||||
//addBody(std::make_shared<RigidBody>(Mesh(ObjectNameTag("Test" + std::to_string(rand())), std::vector<Triangle>({triangleRED}))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntersectionInformation{point, sqrt(minDistance), triangle, ObjectNameTag(bodyName), intersectedBody, intersected};
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::loadMap(const std::string &filename, const Vec3D &scale) {
|
|
||||||
auto objs = ResourceManager::loadObjects(filename);
|
|
||||||
for (auto &i : objs) {
|
|
||||||
std::shared_ptr<RigidBody> obj = std::make_shared<RigidBody>(*i, false);
|
|
||||||
addBody(obj);
|
|
||||||
obj->scale(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::removeBody(const ObjectNameTag &tag) {
|
|
||||||
if (_objects.erase(tag) > 0) {
|
|
||||||
Log::log("World::removeBody(): removed body '" + tag.str() + "'");
|
|
||||||
} else {
|
|
||||||
Log::log("World::removeBody(): cannot remove body '" + tag.str() + "': body does not exist.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::checkCollision(const ObjectNameTag &tag) {
|
|
||||||
if (_objects[tag]->hasCollision()) {
|
|
||||||
|
|
||||||
_objects[tag]->setInCollision(false);
|
|
||||||
|
|
||||||
for (auto it = _objects.begin(); it != _objects.end();) {
|
|
||||||
auto obj = it->second;
|
|
||||||
ObjectNameTag name = it->first;
|
|
||||||
it++;
|
|
||||||
|
|
||||||
if ((name == tag) || !(obj->isCollider() || obj->isTrigger())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, Simplex> gjk = _objects[tag]->checkGJKCollision(obj);
|
|
||||||
if (gjk.first) {
|
|
||||||
if (obj->isCollider()) {
|
|
||||||
CollisionPoint epa = _objects[tag]->EPA(gjk.second, obj);
|
|
||||||
_objects[tag]->solveCollision(epa);
|
|
||||||
}
|
|
||||||
if (_objects[tag]->collisionCallBack() != nullptr) {
|
|
||||||
_objects[tag]->collisionCallBack()(name, obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void World::update() {
|
|
||||||
for (auto &[nameTag, obj] : _objects) {
|
|
||||||
obj->updatePhysicsState();
|
|
||||||
checkCollision(nameTag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<RigidBody> World::body(const ObjectNameTag &tag) {
|
|
||||||
if (_objects.count(tag) == 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return _objects.find(tag)->second;
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_WORLD_H
|
|
||||||
#define ENGINE_WORLD_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Camera.h"
|
|
||||||
#include "io/Screen.h"
|
|
||||||
#include "physics/RigidBody.h"
|
|
||||||
|
|
||||||
struct IntersectionInformation final {
|
|
||||||
const Vec3D pointOfIntersection;
|
|
||||||
const double distanceToObject;
|
|
||||||
const Triangle intersectedTriangle;
|
|
||||||
const ObjectNameTag objectName;
|
|
||||||
const std::shared_ptr<RigidBody> obj;
|
|
||||||
const bool intersected;
|
|
||||||
};
|
|
||||||
|
|
||||||
class World final {
|
|
||||||
private:
|
|
||||||
std::map<ObjectNameTag, std::shared_ptr<RigidBody>> _objects;
|
|
||||||
|
|
||||||
void checkCollision(const ObjectNameTag &tag);
|
|
||||||
public:
|
|
||||||
World() = default;
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
std::shared_ptr<RigidBody> addBody(std::shared_ptr<RigidBody> mesh);
|
|
||||||
std::shared_ptr<RigidBody> body(const ObjectNameTag &tag);
|
|
||||||
void removeBody(const ObjectNameTag &tag);
|
|
||||||
std::shared_ptr<RigidBody> loadBody(const ObjectNameTag &tag, const std::string &filename, const Vec3D &scale = Vec3D{1, 1, 1});
|
|
||||||
void loadMap(const std::string &filename, const Vec3D &scale = Vec3D{1, 1, 1});
|
|
||||||
|
|
||||||
// std::string skipTags is a string that consist of all objects we want to skip in ray casting
|
|
||||||
IntersectionInformation rayCast(const Vec3D &from, const Vec3D &to, const std::string &skipTags = "");
|
|
||||||
|
|
||||||
std::map<ObjectNameTag, std::shared_ptr<RigidBody>>::iterator begin() { return _objects.begin(); }
|
|
||||||
std::map<ObjectNameTag, std::shared_ptr<RigidBody>>::iterator end() { return _objects.end(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_WORLD_H
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 01.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_AATTRACTTOPOINT_H
|
|
||||||
#define SHOOTER_AATTRACTTOPOINT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class AAttractToPoint : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _targetPoint;
|
|
||||||
const double _valueToAttract;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->attractToPoint(_targetPoint, _valueToAttract * dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AAttractToPoint(std::weak_ptr<Object> object, const Vec3D &targetPoint, double valueToAttract, double duration = 1,
|
|
||||||
Animation::LoopOut looped = LoopOut::None,
|
|
||||||
Animation::InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _object(object), _targetPoint(targetPoint),
|
|
||||||
_valueToAttract(valueToAttract) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_AATTRACTTOPOINT_H
|
|
|
@ -1,48 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 02.06.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ACOLOR_H
|
|
||||||
#define ENGINE_ACOLOR_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
|
|
||||||
class AColor final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Mesh> _mesh;
|
|
||||||
|
|
||||||
sf::Color _startColor;
|
|
||||||
const sf::Color _newColor;
|
|
||||||
bool _started = false;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto mesh = _mesh.lock();
|
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_started) {
|
|
||||||
_started = true;
|
|
||||||
_startColor = mesh->color();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D start(_startColor.r, _startColor.g, _startColor.b, _startColor.a);
|
|
||||||
Vec4D end(_newColor.r, _newColor.g, _newColor.b, _newColor.a);
|
|
||||||
Vec4D mid = start + (end - start) * progress();
|
|
||||||
|
|
||||||
mesh->setColor(sf::Color(static_cast<sf::Uint8>(mid.x()), static_cast<sf::Uint8>(mid.y()),
|
|
||||||
static_cast<sf::Uint8>(mid.z()), static_cast<sf::Uint8>(mid.w())));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AColor(std::weak_ptr<Mesh> mesh, const sf::Color &color, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Linear) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_mesh(mesh), _newColor(color) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_3DZAVR_ACOLOR_H
|
|
|
@ -1,50 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 23.02.2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef INC_3DZAVR_ADECOMPOSE_H
|
|
||||||
#define INC_3DZAVR_ADECOMPOSE_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
class ADecompose final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Mesh> _mesh;
|
|
||||||
std::vector<Triangle> _triangles;
|
|
||||||
|
|
||||||
double _value;
|
|
||||||
bool _started = false;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto mesh = _mesh.lock();
|
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_started) {
|
|
||||||
_started = true;
|
|
||||||
_triangles = _mesh.lock()->triangles();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Triangle> newTriangles;
|
|
||||||
newTriangles.reserve(_triangles.size());
|
|
||||||
|
|
||||||
for(auto &t : _triangles) {
|
|
||||||
newTriangles.emplace_back((t * Matrix4x4::Translation(t.position().normalized()*progress()*_value)));
|
|
||||||
}
|
|
||||||
mesh->setTriangles(std::move(newTriangles));
|
|
||||||
mesh->glFreeFloatArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ADecompose(std::weak_ptr<Mesh> mesh, double value, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_value(value), _mesh(mesh) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_ADECOMPOSE_H
|
|
|
@ -1,30 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 06.04.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_AFUNCTION_H
|
|
||||||
#define ENGINE_AFUNCTION_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
|
|
||||||
class AFunction final : public Animation {
|
|
||||||
private:
|
|
||||||
int _callsCounter = 0;
|
|
||||||
const int _allCalls = 1;
|
|
||||||
const std::function<void()> _callBack;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
if (_allCalls != 0 && progress() >= (double) (_callsCounter + 1) / _allCalls) {
|
|
||||||
_callsCounter++;
|
|
||||||
_callBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AFunction(std::function<void()> function, int calls = 1, double duration = 1,
|
|
||||||
LoopOut looped = LoopOut::None, InterpolationType interpolationType = InterpolationType::Linear)
|
|
||||||
: Animation(duration, looped, interpolationType), _callBack(std::move(function)), _allCalls(calls) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //MINECRAFT_3DZAVR_AFUNCTION_H
|
|
|
@ -1,34 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 29.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_AROTATE_H
|
|
||||||
#define ENGINE_AROTATE_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class ARotate final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _rotationValue;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->rotate(_rotationValue * dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ARotate(std::weak_ptr<Object> object, const Vec3D &r, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _object(object), _rotationValue(r) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_AROTATE_H
|
|
|
@ -1,33 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 01.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_AROTATELEFT_H
|
|
||||||
#define SHOOTER_AROTATELEFT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class ARotateLeft final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const double _rotationValue;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->rotateLeft(_rotationValue*dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ARotateLeft(std::weak_ptr<Object> object, double r, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _object(object), _rotationValue(r) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_AROTATELEFT_H
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 01.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_AROTATELEFTUPLOOKAT_H
|
|
||||||
#define SHOOTER_AROTATELEFTUPLOOKAT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
|
|
||||||
class ARotateLeftUpLookAt final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _rotationValue;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->rotateLeft(_rotationValue.x()*dprogress());
|
|
||||||
obj->rotateUp(_rotationValue.y()*dprogress());
|
|
||||||
obj->rotateLookAt(_rotationValue.z()*dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ARotateLeftUpLookAt(std::weak_ptr<Object> object, const Vec3D &r, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _object(object), _rotationValue(r) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_AROTATELEFT_H
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 01.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_AROTATERELATIVEPOINT_H
|
|
||||||
#define SHOOTER_AROTATERELATIVEPOINT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class ARotateRelativePoint : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _targetPoint;
|
|
||||||
const Vec3D _rotationValue;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->rotateRelativePoint(_targetPoint, _rotationValue * dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ARotateRelativePoint(std::weak_ptr<Object> object, const Vec3D &targetPoint, const Vec3D &rotationValue,
|
|
||||||
double duration = 1, Animation::LoopOut looped = LoopOut::None,
|
|
||||||
Animation::InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _object(object), _targetPoint(targetPoint),
|
|
||||||
_rotationValue(rotationValue) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_AROTATERELATIVEPOINT_H
|
|
|
@ -1,39 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 29.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ASCALE_H
|
|
||||||
#define ENGINE_ASCALE_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class AScale final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _scalingValue;
|
|
||||||
Vec3D _prevScaleFactor{1, 1, 1};
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// invert scale
|
|
||||||
obj->scale(Vec3D(1.0/_prevScaleFactor.x(), 1.0/_prevScaleFactor.y(), 1.0/_prevScaleFactor.z()));
|
|
||||||
Vec3D scaleFactor = Vec3D{1, 1, 1} + (_scalingValue - Vec3D{1, 1, 1}) * progress();
|
|
||||||
obj->scale(scaleFactor);
|
|
||||||
_prevScaleFactor = scaleFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AScale(std::weak_ptr<Object> object, const Vec3D &s, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_object(object), _scalingValue(s) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_ASCALE_H
|
|
|
@ -1,59 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 10.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_ASHOWCREATION_H
|
|
||||||
#define SHOOTER_ASHOWCREATION_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
|
|
||||||
class AShowCreation final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Mesh> _mesh;
|
|
||||||
const std::vector<Triangle> _triangles;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto mesh = _mesh.lock();
|
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Triangle> newTriangles;
|
|
||||||
newTriangles.reserve(_triangles.size());
|
|
||||||
|
|
||||||
double shift = 0.95/_triangles.size();
|
|
||||||
double oneTriangleTime = 1.0 - shift*_triangles.size();
|
|
||||||
|
|
||||||
double k = 0.0;
|
|
||||||
for(auto &t : _triangles) {
|
|
||||||
if(progress() >= shift*k) {
|
|
||||||
|
|
||||||
if(progress() <= shift*k + oneTriangleTime) {
|
|
||||||
double triProgressLinear = (progress() - shift*k) / oneTriangleTime;
|
|
||||||
double triProgressBezier = Interpolation::Bezier(Consts::BEZIER[0], Consts::BEZIER[1], triProgressLinear);
|
|
||||||
newTriangles.emplace_back(t[0], t[1], t[1] + (t[2] - t[1]) * triProgressBezier, sf::Color(t.color().r, t.color().g, t.color().b, t.color().a*triProgressBezier));
|
|
||||||
} else {
|
|
||||||
newTriangles.emplace_back(t[0], t[1], t[2], t.color());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
newTriangles.emplace_back(t[0], t[0], t[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
k = k + 1.0;
|
|
||||||
}
|
|
||||||
mesh->setTriangles(std::move(newTriangles));
|
|
||||||
mesh->glFreeFloatArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AShowCreation(std::weak_ptr<Mesh> mesh, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_mesh(mesh), _triangles(mesh.lock()->triangles()) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_ASHOWCREATION_H
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 10.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_ASHOWUNCREATION_H
|
|
||||||
#define SHOOTER_ASHOWUNCREATION_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
|
|
||||||
class AShowUncreation final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Mesh> _mesh;
|
|
||||||
const std::vector<Triangle> _triangles;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto mesh = _mesh.lock();
|
|
||||||
|
|
||||||
if (mesh == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Triangle> newTriangles;
|
|
||||||
newTriangles.reserve(_triangles.size());
|
|
||||||
|
|
||||||
double shift = 0.95/_triangles.size();
|
|
||||||
double oneTriangleTime = 1.0 - shift*_triangles.size();
|
|
||||||
|
|
||||||
double k = 0.0;
|
|
||||||
|
|
||||||
double progress_inv = 1 - progress();
|
|
||||||
|
|
||||||
for(auto &t : _triangles) {
|
|
||||||
if(progress_inv >= shift*k) {
|
|
||||||
if(progress_inv <= shift*k + oneTriangleTime) {
|
|
||||||
double triProgressLinear = (progress_inv - shift*k) / oneTriangleTime;
|
|
||||||
double triProgressBezier = Interpolation::Bezier(Consts::BEZIER[0], Consts::BEZIER[1], triProgressLinear);
|
|
||||||
newTriangles.emplace_back(t[0], t[1], t[1] + (t[2] - t[1]) * triProgressBezier, sf::Color(t.color().r, t.color().g, t.color().b, t.color().a*triProgressBezier));
|
|
||||||
} else {
|
|
||||||
newTriangles.emplace_back(t[0], t[1], t[2], t.color());
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
newTriangles.emplace_back(t[0], t[0], t[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
k = k + 1.0;
|
|
||||||
}
|
|
||||||
mesh->setTriangles(std::move(newTriangles));
|
|
||||||
mesh->glFreeFloatArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
AShowUncreation(std::weak_ptr<Mesh> mesh, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_mesh(mesh), _triangles(mesh.lock()->triangles()) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_ASHOWUNCREATION_H
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 29.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ATRANSLATE_H
|
|
||||||
#define ENGINE_ATRANSLATE_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class ATranslate final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _translationValue;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj->translate(_translationValue * dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ATranslate(std::weak_ptr<Object> object, const Vec3D &t, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier) : Animation(duration, looped,
|
|
||||||
interpolationType),
|
|
||||||
_object(object),
|
|
||||||
_translationValue(t) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_ATRANSLATE_H
|
|
|
@ -1,41 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 29.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ATRANSLATETOPOINT_H
|
|
||||||
#define ENGINE_ATRANSLATETOPOINT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Object.h"
|
|
||||||
|
|
||||||
class ATranslateToPoint final : public Animation {
|
|
||||||
private:
|
|
||||||
const std::weak_ptr<Object> _object;
|
|
||||||
const Vec3D _targetPoint;
|
|
||||||
Vec3D _translationValue;
|
|
||||||
|
|
||||||
bool _started = false;
|
|
||||||
|
|
||||||
void update() override {
|
|
||||||
auto obj = _object.lock();
|
|
||||||
|
|
||||||
if (obj == nullptr) {
|
|
||||||
stop();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_started) {
|
|
||||||
_started = true;
|
|
||||||
_translationValue = _targetPoint - _object.lock()->position();
|
|
||||||
}
|
|
||||||
obj->translate(_translationValue * dprogress());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ATranslateToPoint(std::weak_ptr<Object> object, const Vec3D &p, double duration = 1, LoopOut looped = LoopOut::None,
|
|
||||||
InterpolationType interpolationType = InterpolationType::Bezier)
|
|
||||||
: Animation(duration, looped, interpolationType), _targetPoint(p), _object(object) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_ATRANSLATETOPOINT_H
|
|
|
@ -1,19 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 29.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_AWAIT_H
|
|
||||||
#define ENGINE_AWAIT_H
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
|
|
||||||
class AWait final : public Animation {
|
|
||||||
private:
|
|
||||||
void update() override {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit AWait(double duration = 1) : Animation(duration, LoopOut::None, InterpolationType::Linear, true) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_AWAIT_H
|
|
|
@ -1,60 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 27.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
|
|
||||||
Animation::Animation(double duration, Animation::LoopOut looped, Animation::InterpolationType intType, bool waitForFinish)
|
|
||||||
: _duration(duration), _looped(looped), _intType(intType), _waitForFinish(waitForFinish) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Animation::updateState() {
|
|
||||||
if (_finished || std::abs(_duration) < Consts::EPS) {
|
|
||||||
_finished = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// linear normalized time:
|
|
||||||
_dtime = Time::deltaTime() / _duration;
|
|
||||||
|
|
||||||
switch (_intType) {
|
|
||||||
case InterpolationType::Bezier:
|
|
||||||
_dprogress = Interpolation::dBezier(Consts::BEZIER[0], Consts::BEZIER[1], _time, _dtime);
|
|
||||||
break;
|
|
||||||
case InterpolationType::Bouncing:
|
|
||||||
_dprogress = Interpolation::dBouncing(_time, _dtime);
|
|
||||||
break;
|
|
||||||
case InterpolationType::Linear:
|
|
||||||
_dprogress = Interpolation::dLinear(_time, _dtime);
|
|
||||||
break;
|
|
||||||
case InterpolationType::Cos:
|
|
||||||
_dprogress = Interpolation::dCos(_time, _dtime);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::logic_error{
|
|
||||||
"Animation::updateState: unknown interpolation type " + std::to_string(static_cast<int>(_intType))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_time + _dtime > 1.0) {
|
|
||||||
_dtime = 1.0 - _time;
|
|
||||||
_time = 1.0;
|
|
||||||
_dprogress = 1.0 - _progress;
|
|
||||||
_progress = 1.0;
|
|
||||||
_finished = true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
_time += _dtime;
|
|
||||||
_progress += _dprogress;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_looped == LoopOut::Continue && _time > 0.5) {
|
|
||||||
_time = 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
|
|
||||||
return !_finished;
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_ANIMATION_H
|
|
||||||
#define ENGINE_ANIMATION_H
|
|
||||||
|
|
||||||
#include "Interpolation.h"
|
|
||||||
|
|
||||||
class Animation {
|
|
||||||
public:
|
|
||||||
enum class InterpolationType {
|
|
||||||
Linear,
|
|
||||||
Cos,
|
|
||||||
Bezier,
|
|
||||||
Bouncing
|
|
||||||
};
|
|
||||||
enum class LoopOut {
|
|
||||||
None,
|
|
||||||
Continue
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
// normalized time (from 0 to 1)
|
|
||||||
double _time = 0;
|
|
||||||
double _dtime = 0;
|
|
||||||
|
|
||||||
bool _finished = false;
|
|
||||||
|
|
||||||
double _progress = 0;
|
|
||||||
double _dprogress = 0;
|
|
||||||
|
|
||||||
// If '_waitForFinish' == true then we need to finish all animation before starting this one. (for example AWait)
|
|
||||||
// In addition new animations in particular animation list will be started only after finishing this animation.
|
|
||||||
const bool _waitForFinish;
|
|
||||||
const double _duration = 0;
|
|
||||||
const LoopOut _looped = LoopOut::None;
|
|
||||||
const InterpolationType _intType = InterpolationType::Bezier;
|
|
||||||
|
|
||||||
// You should override this method for your particular animation
|
|
||||||
virtual void update() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
[[nodiscard]] double progress() const { return _progress; }
|
|
||||||
[[nodiscard]] double dprogress() const { return _dprogress; }
|
|
||||||
|
|
||||||
void stop() { _finished = true; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
Animation(double duration, LoopOut looped, InterpolationType intType, bool waitForFinish = false);
|
|
||||||
|
|
||||||
virtual ~Animation() = default;
|
|
||||||
|
|
||||||
bool updateState();
|
|
||||||
|
|
||||||
[[nodiscard]] bool isWaitingForFinish() const { return _waitForFinish; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_ANIMATION_H
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 09.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_ANIMATIONS_H
|
|
||||||
#define SHOOTER_ANIMATIONS_H
|
|
||||||
|
|
||||||
#include "Timeline.h"
|
|
||||||
|
|
||||||
#include "AAttractToPoint.h"
|
|
||||||
#include "AColor.h"
|
|
||||||
#include "AFunction.h"
|
|
||||||
#include "ARotate.h"
|
|
||||||
#include "ARotateLeft.h"
|
|
||||||
#include "ARotateRelativePoint.h"
|
|
||||||
#include "AScale.h"
|
|
||||||
#include "ATranslate.h"
|
|
||||||
#include "ATranslateToPoint.h"
|
|
||||||
#include "AWait.h"
|
|
||||||
#include "AShowCreation.h"
|
|
||||||
#include "AShowUncreation.h"
|
|
||||||
#include "ARotateLeftUpLookAt.h"
|
|
||||||
#include "ADecompose.h"
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_ANIMATIONS_H
|
|
|
@ -1,71 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 09.11.2021.
|
|
||||||
//
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "Interpolation.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
double Interpolation::Linear(double t) {
|
|
||||||
if (t < 0) {
|
|
||||||
t = -t;
|
|
||||||
}
|
|
||||||
int integer = static_cast<int>(t);
|
|
||||||
|
|
||||||
return (integer % 2) ? 1.0 - (t - integer) : (t - integer);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Interpolation::Bezier(const Vec2D &p1, const Vec2D &p2, double t) {
|
|
||||||
// TODO: implement bezier curve without finding the root of equation
|
|
||||||
t = Interpolation::Linear(t);
|
|
||||||
|
|
||||||
double h = Consts::EPS;
|
|
||||||
double eps = Consts::EPS;
|
|
||||||
|
|
||||||
// We are trying to find 's' when px = t
|
|
||||||
auto f = [=](double s) {
|
|
||||||
return 3.0 * (1.0 - s) * (1.0 - s) * s * p1.x() + 3.0 * (1.0 - s) * s * s * p2.x() + s * s * s - t;
|
|
||||||
};
|
|
||||||
// Using found 's' we will calculate resulting py
|
|
||||||
auto py = [=](double s) {
|
|
||||||
return 3.0 * (1.0 - s) * (1.0 - s) * s * p1.y() + 3.0 * (1.0 - s) * s * s * p2.y() + s * s * s;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto df = [=](double s) {
|
|
||||||
return (f(s + h) - f(s - h)) / (2.0 * h);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Newton method
|
|
||||||
double s1 = 0.0, s2 = 0.5;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
while (std::abs(s1 - s2) > eps) {
|
|
||||||
s1 = s2;
|
|
||||||
s2 = s1 - f(s1) / df(s1);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return py(s1);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Interpolation::Bouncing(double t) {
|
|
||||||
t = Interpolation::Linear(t);
|
|
||||||
return 0.5 * (1.0 / (1.0 + exp(10.0 * (-4.0 * t + 0.8))) +
|
|
||||||
(1.0 + 2.5 * sin(50.0 * (t - 1.0 / 3.0)) * exp(-7.0 * t)) / (1.0 + exp(10.0 * (-15.0 * t + 3.1))));
|
|
||||||
}
|
|
||||||
|
|
||||||
double Interpolation::dLinear(double t, double dt) {
|
|
||||||
return ((int) trunc(t) % 2) ? -dt : dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Interpolation::dCos(double t, double dt) {
|
|
||||||
return 0.5 * Consts::PI * sin(Consts::PI * t) * 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
double Interpolation::dBouncing(double t, double dt) {
|
|
||||||
return Bouncing(t + dt) - Bouncing(t);
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_INTERPOLATION_H
|
|
||||||
#define ENGINE_INTERPOLATION_H
|
|
||||||
|
|
||||||
#include "../math/Vec2D.h"
|
|
||||||
|
|
||||||
namespace Interpolation {
|
|
||||||
double Linear(double t);
|
|
||||||
|
|
||||||
double Bezier(const Vec2D &p1, const Vec2D &p2, double t);
|
|
||||||
|
|
||||||
double Bouncing(double t);
|
|
||||||
|
|
||||||
double dLinear(double t, double dt);
|
|
||||||
|
|
||||||
double dCos(double t, double dt);
|
|
||||||
|
|
||||||
double dBezier(const Vec2D &p1, const Vec2D &p2, double t, double dt);
|
|
||||||
|
|
||||||
double dBouncing(double t, double dt);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_INTERPOLATION_H
|
|
|
@ -1,96 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 03.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "Timeline.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
|
|
||||||
Timeline *Timeline::_instance = nullptr;
|
|
||||||
|
|
||||||
void Timeline::init() {
|
|
||||||
delete _instance;
|
|
||||||
_instance = new Timeline();
|
|
||||||
|
|
||||||
Log::log("Timeline::init(): animation timeline was initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::deleteAllAnimations() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("Timeline::deleteAllAnimations(): all " + std::to_string(_instance->_animations.size()) + " list was deleted");
|
|
||||||
_instance->_animations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::deleteAnimationList(const AnimationListTag &listName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = _instance->_animations.find(listName);
|
|
||||||
|
|
||||||
if(it != _instance->_animations.end()) {
|
|
||||||
_instance->_animations.erase(it);
|
|
||||||
} else {
|
|
||||||
Log::log("Timeline::deleteAnimationList(): list '" + listName.str() + "' does not exist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool Timeline::isInAnimList(const AnimationListTag &listName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = _instance->_animations.find(listName);
|
|
||||||
if(it != _instance->_animations.end()) {
|
|
||||||
return !it->second.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::update() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto iter = _instance->_animations.begin(); iter != _instance->_animations.end(); ) {
|
|
||||||
if (iter->second.empty()) {
|
|
||||||
_instance->_animations.erase(iter++);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto& animationList = iter->second;
|
|
||||||
auto it = animationList.begin();
|
|
||||||
|
|
||||||
// If it the front animation is 'AWait' we should wait until waiting time is over
|
|
||||||
if ((it != animationList.end()) && (*it)->isWaitingForFinish()) {
|
|
||||||
if (!(*it)->updateState()) {
|
|
||||||
animationList.erase(it);
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise we iterate over all animation until we meet animations.end() or wait animation
|
|
||||||
while (!animationList.empty() && (it != animationList.end()) && (!(*it)->isWaitingForFinish())) {
|
|
||||||
if (!(*it)->updateState()) {
|
|
||||||
animationList.erase(it++);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timeline::free() {
|
|
||||||
Timeline::deleteAllAnimations();
|
|
||||||
|
|
||||||
delete _instance;
|
|
||||||
_instance = nullptr;
|
|
||||||
|
|
||||||
Log::log("Timeline::free(): pointer to 'Timeline' was freed");
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 03.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_TIMELINE_H
|
|
||||||
#define SHOOTER_TIMELINE_H
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Animation.h"
|
|
||||||
|
|
||||||
class AnimationListTag final {
|
|
||||||
private:
|
|
||||||
const std::string _name;
|
|
||||||
public:
|
|
||||||
explicit AnimationListTag(std::string name = "") : _name(std::move(name)) {}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string str() const { return _name; }
|
|
||||||
|
|
||||||
bool operator==(const AnimationListTag &tag) const { return _name == tag._name; }
|
|
||||||
|
|
||||||
bool operator!=(const AnimationListTag &tag) const { return _name != tag._name; }
|
|
||||||
|
|
||||||
bool operator<(const AnimationListTag &tag) const { return _name < tag._name; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class Timeline {
|
|
||||||
private:
|
|
||||||
std::map<AnimationListTag, std::list<std::shared_ptr<Animation>>> _animations;
|
|
||||||
|
|
||||||
static Timeline *_instance;
|
|
||||||
|
|
||||||
Timeline() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Timeline(const Timeline &) = delete;
|
|
||||||
|
|
||||||
Timeline &operator=(Timeline &) = delete;
|
|
||||||
|
|
||||||
static void update();
|
|
||||||
|
|
||||||
static void deleteAllAnimations();
|
|
||||||
|
|
||||||
static void deleteAnimationList(const AnimationListTag &listName);
|
|
||||||
|
|
||||||
[[nodiscard]] static bool isInAnimList(const AnimationListTag &listName);
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
|
|
||||||
static void free();
|
|
||||||
|
|
||||||
template <typename T, typename... Arguments>
|
|
||||||
static void addAnimation(const AnimationListTag &listName, Arguments... args) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance->_animations[listName].emplace_back(std::make_shared<T>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename... Arguments>
|
|
||||||
static void addAnimation(Arguments... args) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance->_animations[AnimationListTag("timeline_0")].emplace_back(std::make_shared<T>(args...));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_TIMELINE_H
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,62 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Button.h"
|
|
||||||
#include "../utils/ResourceManager.h"
|
|
||||||
|
|
||||||
void Button::select() {
|
|
||||||
if (!_selected && !_pressed) {
|
|
||||||
_button.setTextureRect(sf::IntRect(_selectedState.tx, _selectedState.ty, _w, _h));
|
|
||||||
_selected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::unSelect() {
|
|
||||||
if (_selected && !_pressed) {
|
|
||||||
_button.setTextureRect(sf::IntRect(_usualState.tx, _usualState.ty, _w, _h));
|
|
||||||
_selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::press() {
|
|
||||||
if (!_pressed) {
|
|
||||||
_button.setTextureRect(sf::IntRect(_pressedState.tx, _pressedState.ty, _w, _h));
|
|
||||||
if (_checkBox) {
|
|
||||||
_pressed = true;
|
|
||||||
}
|
|
||||||
_click();
|
|
||||||
} else {
|
|
||||||
_button.setTextureRect(sf::IntRect(_usualState.tx, _usualState.ty, _w, _h));
|
|
||||||
if (_checkBox) {
|
|
||||||
_pressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Button::init() {
|
|
||||||
_button.setTexture(*ResourceManager::loadTexture(_texture));
|
|
||||||
_button.setTextureRect(sf::IntRect(_usualState.tx, _usualState.ty, _w, _h));
|
|
||||||
_button.scale(static_cast<float>(_sx), static_cast<float>(_sy));
|
|
||||||
_button.setPosition(static_cast<float>(_x) - static_cast<float>(_w * _sx) / 2.0f,
|
|
||||||
static_cast<float>(_y) - static_cast<float>(_h * _sy) / 2.0f);
|
|
||||||
|
|
||||||
_text.setFont(*ResourceManager::loadFont(_font));
|
|
||||||
_text.setString(_textString);
|
|
||||||
_text.setCharacterSize(static_cast<unsigned int>((_h * _sy) / 2));
|
|
||||||
_text.setFillColor(_textColor);
|
|
||||||
_text.setPosition(static_cast<float>(_x) - _text.getLocalBounds().width / 2.0f,
|
|
||||||
static_cast<float>(_y) - static_cast<float>(_h * _sy) / 2.0f + _text.getLocalBounds().height / 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Button::Button(int x, int y, int width, int height, std::function<void()> click, std::string text, double sx,
|
|
||||||
double sy, std::string texture, tPos usualState, tPos selectedState, tPos pressedState,
|
|
||||||
std::string font, sf::Color textColor) : _x(x), _y(y), _w(width), _h(height), _click(std::move(click)),
|
|
||||||
_textString(std::move(text)), _sx(sx), _sy(sy),
|
|
||||||
_texture(std::move(texture)), _usualState(usualState),
|
|
||||||
_selectedState(selectedState), _pressedState(pressedState),
|
|
||||||
_font(std::move(font)), _textColor(textColor) {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_BUTTON_H
|
|
||||||
#define ENGINE_BUTTON_H
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
struct tPos final {
|
|
||||||
const int tx;
|
|
||||||
const int ty;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Button final {
|
|
||||||
private:
|
|
||||||
const int _x{};
|
|
||||||
const int _y{};
|
|
||||||
|
|
||||||
const int _w{};
|
|
||||||
const int _h{};
|
|
||||||
|
|
||||||
const std::function<void()> _click;
|
|
||||||
|
|
||||||
const std::string _textString;
|
|
||||||
|
|
||||||
const double _sx{};
|
|
||||||
const double _sy{};
|
|
||||||
|
|
||||||
const std::string _texture;
|
|
||||||
const tPos _usualState{};
|
|
||||||
const tPos _selectedState{};
|
|
||||||
const tPos _pressedState{};
|
|
||||||
|
|
||||||
const std::string _font;
|
|
||||||
const sf::Color _textColor;
|
|
||||||
|
|
||||||
sf::Sprite _button;
|
|
||||||
sf::Text _text;
|
|
||||||
|
|
||||||
bool _selected = false;
|
|
||||||
bool _pressed = false;
|
|
||||||
bool _checkBox = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Button() = default;
|
|
||||||
|
|
||||||
Button(int x, int y, int width, int height, std::function<void()> click, std::string text, double sx, double sy,
|
|
||||||
std::string texture, tPos usualState, tPos selectedState, tPos pressedState, std::string font,
|
|
||||||
sf::Color textColor);
|
|
||||||
|
|
||||||
void select();
|
|
||||||
|
|
||||||
void unSelect();
|
|
||||||
|
|
||||||
void press();
|
|
||||||
|
|
||||||
void init();
|
|
||||||
|
|
||||||
[[nodiscard]] int x() const { return _x; }
|
|
||||||
|
|
||||||
[[nodiscard]] int y() const { return _y; }
|
|
||||||
|
|
||||||
[[nodiscard]] int w() const { return _w; }
|
|
||||||
|
|
||||||
[[nodiscard]] int h() const { return _h; }
|
|
||||||
|
|
||||||
[[nodiscard]] double sx() const { return _sx; }
|
|
||||||
|
|
||||||
[[nodiscard]] double sy() const { return _sy; }
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Sprite const &sprite() const { return _button; }
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Text const &text() const { return _text; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //MINECRAFT_3DZAVR_BUTTON_H
|
|
|
@ -1,57 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Window.h"
|
|
||||||
#include "../utils/ResourceManager.h"
|
|
||||||
|
|
||||||
void Window::addButton(int x, int y, int w, int h, std::function<void()> click, const std::string &text, double sx,
|
|
||||||
double sy,
|
|
||||||
const std::string &texture, tPos usualState, tPos selectedState, tPos pressedState,
|
|
||||||
const std::string &font, sf::Color textColor) {
|
|
||||||
_buttons.emplace_back(x, y, w, h, std::move(click), text, sx, sy, texture, usualState, selectedState, pressedState,
|
|
||||||
font, textColor);
|
|
||||||
_buttons.back().init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::update() {
|
|
||||||
|
|
||||||
_screen->setTitle(_name);
|
|
||||||
_screen->drawSprite(_back);
|
|
||||||
|
|
||||||
Vec2D mousePos = _mouse->getMousePosition();
|
|
||||||
Vec2D dMousePos = mousePos - _prevMousePosition;
|
|
||||||
_prevMousePosition = mousePos;
|
|
||||||
_back.setPosition(_back.getPosition() - sf::Vector2f(static_cast<float>(dMousePos.x()) / 30.0f,
|
|
||||||
static_cast<float>(dMousePos.y()) / 30.0f));
|
|
||||||
bool isPressed = _mouse->isButtonTapped(sf::Mouse::Left);
|
|
||||||
|
|
||||||
for (auto &button : _buttons) {
|
|
||||||
if (mousePos.x() > button.x() - button.w() * button.sx() / 2.0f &&
|
|
||||||
mousePos.y() > button.y() - button.h() * button.sy() / 2.0f &&
|
|
||||||
mousePos.x() < button.x() + button.w() * button.sx() / 2.0f &&
|
|
||||||
mousePos.y() < button.y() + button.h() * button.sy() / 2.0f) {
|
|
||||||
button.select();
|
|
||||||
if (isPressed)
|
|
||||||
button.press();
|
|
||||||
} else {
|
|
||||||
button.unSelect();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_screen->isOpen()) {
|
|
||||||
_screen->drawSprite(button.sprite());
|
|
||||||
_screen->drawText(button.text());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::setBackgroundTexture(const std::string &texture, double sx, double sy, int w, int h) {
|
|
||||||
_backTexture = texture;
|
|
||||||
std::shared_ptr<sf::Texture> t = ResourceManager::loadTexture(_backTexture);
|
|
||||||
t->setRepeated(true);
|
|
||||||
_back = sf::Sprite(*t, sf::IntRect(0, 0, static_cast<int>(w + w / 30.0), static_cast<int>(h + h / 30.0)));
|
|
||||||
_back.scale((float) sx, (float) sy);
|
|
||||||
_back.setPosition(sf::Vector2f(static_cast<float>(-w) / 30.0f, static_cast<float>(-h) / 30.0f));
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 26.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_WINDOW_H
|
|
||||||
#define ENGINE_WINDOW_H
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "Button.h"
|
|
||||||
#include "../io/Screen.h"
|
|
||||||
#include "../io/Mouse.h"
|
|
||||||
|
|
||||||
class Window final {
|
|
||||||
private:
|
|
||||||
std::string _name;
|
|
||||||
std::string _backTexture;
|
|
||||||
std::vector<Button> _buttons;
|
|
||||||
|
|
||||||
sf::Sprite _back;
|
|
||||||
|
|
||||||
Vec2D _prevMousePosition{0, 0};
|
|
||||||
|
|
||||||
std::shared_ptr<Screen> _screen;
|
|
||||||
std::shared_ptr<Mouse> _mouse;
|
|
||||||
public:
|
|
||||||
explicit Window(std::shared_ptr<Screen> screen, std::shared_ptr<Mouse> mouse, std::string name = "Menu",
|
|
||||||
std::string backTexture = "") : _screen(screen), _mouse(mouse),
|
|
||||||
_name(std::move(name)), _backTexture(std::move(backTexture)) {}
|
|
||||||
|
|
||||||
void addButton(int x, int y, int w, int h,
|
|
||||||
std::function<void()> click,
|
|
||||||
const std::string &text = "_button", double sx = 1, double sy = 1,
|
|
||||||
const std::string &texture = "", tPos usualState = {}, tPos selectedState = {},
|
|
||||||
tPos pressedState = {},
|
|
||||||
const std::string &font = Consts::MEDIUM_FONT, sf::Color textColor = {255, 255, 255});
|
|
||||||
|
|
||||||
void setTitle(const std::string &title) { _name = title; }
|
|
||||||
|
|
||||||
void setBackgroundTexture(const std::string &texture, double sx = 1, double sy = 1, int w = 1920, int h = 1080);
|
|
||||||
|
|
||||||
void update();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //MINECRAFT_3DZAVR_WINDOW_H
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.09.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Keyboard.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
bool Keyboard::isKeyPressed(sf::Keyboard::Key key) {
|
|
||||||
return sf::Keyboard::isKeyPressed(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Keyboard::isKeyTapped(sf::Keyboard::Key key) {
|
|
||||||
if (!Keyboard::isKeyPressed(key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_tappedKeys.count(key) == 0) {
|
|
||||||
_tappedKeys.emplace(key, Time::time());
|
|
||||||
return true;
|
|
||||||
} else if ((Time::time() - _tappedKeys[key]) > Consts::TAP_DELAY) {
|
|
||||||
_tappedKeys[key] = Time::time();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.09.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_KEYBOARD_H
|
|
||||||
#define SHOOTER_KEYBOARD_H
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
class Keyboard final {
|
|
||||||
private:
|
|
||||||
std::map<sf::Keyboard::Key, double> _tappedKeys;
|
|
||||||
public:
|
|
||||||
Keyboard() = default;
|
|
||||||
|
|
||||||
// returns true if this key is _pressed
|
|
||||||
static bool isKeyPressed(sf::Keyboard::Key key);
|
|
||||||
|
|
||||||
// returns true if this key is tapped and 1/5 sec passed (_button bouncing problem solved)
|
|
||||||
bool isKeyTapped(sf::Keyboard::Key key);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_KEYBOARD_H
|
|
|
@ -1,45 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.09.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Mouse.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
Vec2D Mouse::getMousePosition() const {
|
|
||||||
sf::Vector2<int> pos = sf::Mouse::getPosition(*_screen->renderWindow());
|
|
||||||
return Vec2D(pos.x, pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec2D Mouse::getMouseDisplacement() const {
|
|
||||||
sf::Vector2<int> mousePos = sf::Mouse::getPosition(*_screen->renderWindow());
|
|
||||||
sf::Vector2<int> center = sf::Vector2<int>(_screen->width() / 2, _screen->height() / 2);
|
|
||||||
|
|
||||||
sf::Vector2<int> displacement = mousePos - center;
|
|
||||||
setMouseInCenter();
|
|
||||||
return Vec2D(displacement.x, displacement.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mouse::setMouseInCenter() const {
|
|
||||||
sf::Vector2<int> center = sf::Vector2<int>(_screen->width() / 2, _screen->height() / 2);
|
|
||||||
sf::Mouse::setPosition(center,*_screen->renderWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mouse::isButtonPressed(sf::Mouse::Button button) {
|
|
||||||
return sf::Mouse::isButtonPressed(button);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mouse::isButtonTapped(sf::Mouse::Button button) {
|
|
||||||
if (!Mouse::isButtonPressed(button)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_tappedButtons.count(button) == 0) {
|
|
||||||
_tappedButtons.emplace(button, Time::time());
|
|
||||||
return true;
|
|
||||||
} else if ((Time::time() - _tappedButtons[button]) > Consts::TAP_DELAY) {
|
|
||||||
_tappedButtons[button] = Time::time();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.09.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_MOUSE_H
|
|
||||||
#define SHOOTER_MOUSE_H
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Screen.h"
|
|
||||||
#include "../math/Vec2D.h"
|
|
||||||
|
|
||||||
class Mouse final {
|
|
||||||
private:
|
|
||||||
const std::shared_ptr<Screen> _screen;
|
|
||||||
|
|
||||||
std::map<sf::Mouse::Button, double> _tappedButtons;
|
|
||||||
public:
|
|
||||||
explicit Mouse(std::shared_ptr<Screen> screen) : _screen(std::move(screen)) {};
|
|
||||||
|
|
||||||
// returns true if this _button is _pressed
|
|
||||||
static bool isButtonPressed(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);
|
|
||||||
|
|
||||||
[[nodiscard]] Vec2D getMousePosition() const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec2D getMouseDisplacement() const;
|
|
||||||
|
|
||||||
void setMouseInCenter() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_MOUSE_H
|
|
|
@ -1,223 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include <SFML/OpenGL.hpp>
|
|
||||||
|
|
||||||
#include "Screen.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
#include "../utils/ResourceManager.h"
|
|
||||||
|
|
||||||
void Screen::open(int screenWidth, int screenHeight, const std::string &name, bool verticalSync, sf::Color background,
|
|
||||||
sf::Uint32 style) {
|
|
||||||
_title = name;
|
|
||||||
_background = background;
|
|
||||||
|
|
||||||
sf::ContextSettings settings;
|
|
||||||
settings.depthBits = 12;
|
|
||||||
settings.antialiasingLevel = 1;
|
|
||||||
|
|
||||||
_window->create(sf::VideoMode(screenWidth, screenHeight), name, style, settings);
|
|
||||||
_window->setVerticalSyncEnabled(verticalSync);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::display() {
|
|
||||||
sf::Event event{};
|
|
||||||
while (_window->pollEvent(event)) {
|
|
||||||
if (event.type == sf::Event::Closed) {
|
|
||||||
_window->close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string title = _title + " (" + std::to_string(Time::fps()) + " fps)";
|
|
||||||
_window->setTitle(title);
|
|
||||||
|
|
||||||
if(_renderVideo) {
|
|
||||||
sf::Texture copyTexture;
|
|
||||||
copyTexture.create(_window->getSize().x, _window->getSize().y);
|
|
||||||
copyTexture.update(*_window);
|
|
||||||
// most of the time of video rendering is wasting on saving .png sequence
|
|
||||||
// that's why we will save all images in the end
|
|
||||||
// TODO: sometimes we have a huge time delay here for no obvious reason
|
|
||||||
_renderSequence.push_back(copyTexture);
|
|
||||||
}
|
|
||||||
|
|
||||||
_window->display();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::startRender() {
|
|
||||||
stopRender();
|
|
||||||
|
|
||||||
Log::log("Screen::startRender(): start recording the screen");
|
|
||||||
_renderVideo = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::stopRender() {
|
|
||||||
if(_renderVideo) {
|
|
||||||
Log::log("Screen::stopRender(): stop recording the screen");
|
|
||||||
Log::log("Screen::stopRender(): start saving .png sequence");
|
|
||||||
std::string c = "rm film/png/*.png";
|
|
||||||
popen(c.c_str(), "w");
|
|
||||||
int i = 0;
|
|
||||||
for(; i < _renderSequence.size(); i++) {
|
|
||||||
_renderSequence[i].copyToImage().saveToFile("film/png/" + std::to_string(i) + ".png");
|
|
||||||
Log::log("Screen::stopRender(): saving .png sequence (" + std::to_string(static_cast<int>(100*i/_renderSequence.size())) + "%)");
|
|
||||||
}
|
|
||||||
_renderSequence.clear();
|
|
||||||
|
|
||||||
Log::log("Screen::stopRender(): start rendering final video");
|
|
||||||
// TODO: .png sequence looks better than a final video (poor clarity and desaturated colors)
|
|
||||||
c = "ffmpeg -stats -r 60 -i film/png/%d.png -vcodec libx264 -crf 1 -pix_fmt yuv420p -frames " + std::to_string(i) + " film/mp4/" + std::to_string(_scene) + "_" + _title + "_" + std::to_string(rand()) + ".mp4";
|
|
||||||
popen(c.c_str(), "w");
|
|
||||||
_scene++;
|
|
||||||
_renderVideo = false;
|
|
||||||
Log::log("Screen::stopRender(): finish rendering final video");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::clear() {
|
|
||||||
// Clear the depth buffer
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
_window->clear(_background);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::drawTriangle(const Triangle &triangle) {
|
|
||||||
sf::Vertex tris[3] =
|
|
||||||
{
|
|
||||||
sf::Vertex(sf::Vector2f(static_cast<float>(triangle[0].x()), static_cast<float>(triangle[0].y())),
|
|
||||||
triangle.color()),
|
|
||||||
sf::Vertex(sf::Vector2f(static_cast<float>(triangle[1].x()), static_cast<float>(triangle[1].y())),
|
|
||||||
triangle.color()),
|
|
||||||
sf::Vertex(sf::Vector2f(static_cast<float>(triangle[2].x()), static_cast<float>(triangle[2].y())),
|
|
||||||
triangle.color())
|
|
||||||
};
|
|
||||||
|
|
||||||
sf::Vertex lines[4] =
|
|
||||||
{
|
|
||||||
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), sf::Color(0, 0, 0, 255)),
|
|
||||||
sf::Vertex(sf::Vector2f(triangle[1].x(), triangle[1].y()), sf::Color(0, 0, 0, 255)),
|
|
||||||
sf::Vertex(sf::Vector2f(triangle[2].x(), triangle[2].y()), sf::Color(0, 0, 0, 255)),
|
|
||||||
sf::Vertex(sf::Vector2f(triangle[0].x(), triangle[0].y()), sf::Color(0, 0, 0, 255))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Uncomment this line to show boundaries of triangles
|
|
||||||
// Раскомментируйте эту строку для отображения границ треугольников
|
|
||||||
// |
|
|
||||||
// \/
|
|
||||||
_window->draw(lines, 4, sf::LineStrip);
|
|
||||||
|
|
||||||
//_window->draw(tris, 3, sf::Triangles);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::setTitle(const std::string &title) {
|
|
||||||
_title = title;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Screen::isOpen() {
|
|
||||||
return _window->isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::close() {
|
|
||||||
_window->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::setMouseCursorVisible(bool visible) {
|
|
||||||
_window->setMouseCursorVisible(visible);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, const Vec2D &p4, sf::Color color) {
|
|
||||||
sf::ConvexShape polygon;
|
|
||||||
polygon.setPointCount(4);
|
|
||||||
polygon.setPoint(0, sf::Vector2f(static_cast<float>(p1.x()), static_cast<float>(p1.y())));
|
|
||||||
polygon.setPoint(1, sf::Vector2f(static_cast<float>(p2.x()), static_cast<float>(p2.y())));
|
|
||||||
polygon.setPoint(2, sf::Vector2f(static_cast<float>(p3.x()), static_cast<float>(p3.y())));
|
|
||||||
polygon.setPoint(3, sf::Vector2f(static_cast<float>(p4.x()), static_cast<float>(p4.y())));
|
|
||||||
polygon.setFillColor(color);
|
|
||||||
|
|
||||||
_window->draw(polygon);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::drawText(const std::string &string, const Vec2D &position, int size, sf::Color color) {
|
|
||||||
sf::Text text;
|
|
||||||
|
|
||||||
text.setFont(*ResourceManager::loadFont(Consts::MEDIUM_FONT));
|
|
||||||
|
|
||||||
text.setCharacterSize(size);
|
|
||||||
text.setFillColor(color);
|
|
||||||
text.setStyle(sf::Text::Italic);
|
|
||||||
text.setPosition(static_cast<float>(position.x()), static_cast<float>(position.y()));
|
|
||||||
|
|
||||||
text.setString(string);
|
|
||||||
|
|
||||||
_window->draw(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::drawSprite(const sf::Sprite &sprite) {
|
|
||||||
_window->draw(sprite);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Screen::drawText(const sf::Text &text) {
|
|
||||||
_window->draw(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenGL functions
|
|
||||||
void Screen::prepareToGlDrawMesh() {
|
|
||||||
glEnable(GL_CULL_FACE); // enable culling face
|
|
||||||
glCullFace(GL_BACK); // cull faces from back
|
|
||||||
glFrontFace(GL_CCW); // vertex order (counter clock wise)
|
|
||||||
|
|
||||||
// Enable Z-buffer read and write
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthMask(GL_TRUE);
|
|
||||||
glClearDepth(1.f);
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
|
|
||||||
// Disable lighting
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
// enable alpha channel:
|
|
||||||
glEnable( GL_ALPHA_TEST );
|
|
||||||
glAlphaFunc(GL_NOTEQUAL, 0.0);
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
// Configure the viewport (the same size as the window)
|
|
||||||
glViewport(0, 0, _window->getSize().x, _window->getSize().y);
|
|
||||||
|
|
||||||
// Setup a perspective projection
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
|
||||||
glLoadIdentity();
|
|
||||||
GLfloat ratio = static_cast<float>(_window->getSize().x) / _window->getSize().y;
|
|
||||||
glFrustum(-ratio, ratio, -1.f, 1.f, 1.0f, 500.f);
|
|
||||||
|
|
||||||
// Enable position and texture coordinates vertex components
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
// Disable normal and color vertex components
|
|
||||||
glDisableClientState(GL_NORMAL_ARRAY);
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
|
|
||||||
// Prepare to apply some transformations
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenGL functions
|
|
||||||
void Screen::glDrawMesh(GLfloat* geometry, GLfloat* view, GLfloat* model, size_t count) {
|
|
||||||
glVertexPointer(3, GL_FLOAT, 7 * sizeof(GLfloat), geometry);
|
|
||||||
glColorPointer(4, GL_FLOAT, 7 * sizeof(GLfloat), geometry + 3);
|
|
||||||
|
|
||||||
glLoadIdentity();
|
|
||||||
|
|
||||||
glLoadMatrixf(view);
|
|
||||||
glMultMatrixf(model);
|
|
||||||
|
|
||||||
// Draw the mesh
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, count);
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 14.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_SCREEN_H
|
|
||||||
#define ENGINE_SCREEN_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
|
|
||||||
#include "../Triangle.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
#include "../Camera.h"
|
|
||||||
|
|
||||||
class Screen final {
|
|
||||||
private:
|
|
||||||
int _scene = 0;
|
|
||||||
bool _renderVideo = false;
|
|
||||||
std::vector<sf::Texture> _renderSequence;
|
|
||||||
|
|
||||||
std::string _title;
|
|
||||||
|
|
||||||
sf::Color _background;
|
|
||||||
|
|
||||||
const std::shared_ptr<sf::RenderWindow> _window = std::make_shared<sf::RenderWindow>();
|
|
||||||
public:
|
|
||||||
void open(int screenWidth = Consts::STANDARD_SCREEN_WIDTH, int screenHeight = Consts::STANDARD_SCREEN_HEIGHT,
|
|
||||||
const std::string &name = Consts::PROJECT_NAME, bool verticalSync = true,
|
|
||||||
sf::Color background = Consts::BACKGROUND_COLOR, sf::Uint32 style = sf::Style::Default);
|
|
||||||
|
|
||||||
void display();
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
[[nodiscard]] bool hasFocus() const { return _window->hasFocus(); }
|
|
||||||
|
|
||||||
void drawTriangle(const Triangle &triangle);
|
|
||||||
|
|
||||||
void drawTetragon(const Vec2D &p1, const Vec2D &p2, const Vec2D &p3, const Vec2D &p4, sf::Color color);
|
|
||||||
|
|
||||||
void drawText(const std::string &string, const Vec2D &position, int size, sf::Color color);
|
|
||||||
|
|
||||||
void drawText(const sf::Text &text);
|
|
||||||
|
|
||||||
void drawSprite(const sf::Sprite &sprite);
|
|
||||||
|
|
||||||
void setTitle(const std::string &title);
|
|
||||||
|
|
||||||
[[nodiscard]] std::string title() const { return _title; };
|
|
||||||
|
|
||||||
bool isOpen();
|
|
||||||
|
|
||||||
[[nodiscard]] int width() const { return _window->getSize().x; }
|
|
||||||
|
|
||||||
[[nodiscard]] int height() const { return _window->getSize().y; }
|
|
||||||
|
|
||||||
void close();
|
|
||||||
|
|
||||||
void setMouseCursorVisible(bool visible);
|
|
||||||
|
|
||||||
// OpenGL functions
|
|
||||||
void prepareToGlDrawMesh();
|
|
||||||
|
|
||||||
void glDrawMesh(GLfloat *geometry, GLfloat *view, GLfloat *model, size_t count);
|
|
||||||
|
|
||||||
[[nodiscard]] std::shared_ptr<sf::RenderWindow> renderWindow() { return _window; }
|
|
||||||
|
|
||||||
void pushGLStates() { _window->pushGLStates(); };
|
|
||||||
void popGLStates() { _window->popGLStates(); };
|
|
||||||
|
|
||||||
void startRender();
|
|
||||||
void stopRender();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_SCREEN_H
|
|
|
@ -1,86 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 17.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "SoundController.h"
|
|
||||||
#include "../utils/ResourceManager.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
|
|
||||||
SoundController *SoundController::_instance = nullptr;
|
|
||||||
|
|
||||||
|
|
||||||
void SoundController::init() {
|
|
||||||
delete _instance;
|
|
||||||
_instance = new SoundController();
|
|
||||||
|
|
||||||
Log::log("SoundController::init(): sound controller was initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundController::loadAndPlay(const SoundTag &soundTag, const std::string& filename) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (_instance->_sounds.count(soundTag) != 0) {
|
|
||||||
_instance->_sounds[soundTag] = sf::Sound(*ResourceManager::loadSoundBuffer(filename));
|
|
||||||
} else {
|
|
||||||
_instance->_sounds.emplace(soundTag, sf::Sound(*ResourceManager::loadSoundBuffer(filename)));
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance->_sounds[soundTag].play();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundController::playSound(const SoundTag &soundTag) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_instance->_sounds.count(soundTag) != 0) {
|
|
||||||
_instance->_sounds[soundTag].play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundController::pauseSound(const SoundTag &soundTag) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_instance->_sounds.count(soundTag) > 0) {
|
|
||||||
_instance->_sounds[soundTag].pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundController::stopSound(const SoundTag &soundTag) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_instance->_sounds.count(soundTag) > 0) {
|
|
||||||
_instance->_sounds[soundTag].stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Sound::Status SoundController::getStatus(const SoundTag &soundTag) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return sf::Sound::Status::Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_instance->_sounds.count(soundTag) > 0) {
|
|
||||||
return _instance->_sounds[soundTag].getStatus();
|
|
||||||
} else {
|
|
||||||
return sf::Sound::Status::Stopped;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SoundController::free() {
|
|
||||||
if (_instance != nullptr) {
|
|
||||||
for (auto&[soundTag, sound] : _instance->_sounds) {
|
|
||||||
stopSound(soundTag);
|
|
||||||
}
|
|
||||||
_instance->_sounds.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete _instance;
|
|
||||||
_instance = nullptr;
|
|
||||||
|
|
||||||
Log::log("SoundController::free(): pointer to 'SoundController' was freed");
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 17.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_SOUNDCONTROLLER_H
|
|
||||||
#define SHOOTER_SOUNDCONTROLLER_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <SFML/Audio.hpp>
|
|
||||||
|
|
||||||
class SoundTag final {
|
|
||||||
private:
|
|
||||||
const std::string _name;
|
|
||||||
public:
|
|
||||||
explicit SoundTag(std::string name = "") : _name(std::move(name)) {}
|
|
||||||
|
|
||||||
[[nodiscard]] std::string str() const { return _name; }
|
|
||||||
|
|
||||||
bool operator==(const SoundTag &tag) const { return _name == tag._name; }
|
|
||||||
|
|
||||||
bool operator!=(const SoundTag &tag) const { return _name != tag._name; }
|
|
||||||
|
|
||||||
bool operator<(const SoundTag &tag) const { return _name < tag._name; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class SoundController final {
|
|
||||||
private:
|
|
||||||
std::map<SoundTag, sf::Sound> _sounds;
|
|
||||||
|
|
||||||
static SoundController *_instance;
|
|
||||||
|
|
||||||
SoundController() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SoundController(const SoundController &) = delete;
|
|
||||||
|
|
||||||
SoundController &operator=(SoundController &) = delete;
|
|
||||||
|
|
||||||
static void loadAndPlay(const SoundTag &soundTag, const std::string& filename);
|
|
||||||
|
|
||||||
static void playSound(const SoundTag &soundTag);
|
|
||||||
static void pauseSound(const SoundTag &soundTag);
|
|
||||||
static void stopSound(const SoundTag &soundTag);
|
|
||||||
|
|
||||||
static sf::Sound::Status getStatus(const SoundTag &soundTag);
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
|
|
||||||
static void free();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_SOUNDCONTROLLER_H
|
|
|
@ -1,240 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 12.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "Matrix4x4.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::operator*(const Matrix4x4 &matrix4X4) const {
|
|
||||||
Matrix4x4 result = Matrix4x4::Zero();
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
for (int j = 0; j < 4; j++)
|
|
||||||
for (int k = 0; k < 4; k++)
|
|
||||||
result._arr[i][j] += _arr[i][k] * matrix4X4._arr[k][j];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Matrix4x4::operator*(const Vec4D &point4D) const {
|
|
||||||
return Vec4D(
|
|
||||||
_arr[0][0] * point4D.x() + _arr[0][1] * point4D.y() + _arr[0][2] * point4D.z() + _arr[0][3] * point4D.w(),
|
|
||||||
_arr[1][0] * point4D.x() + _arr[1][1] * point4D.y() + _arr[1][2] * point4D.z() + _arr[1][3] * point4D.w(),
|
|
||||||
_arr[2][0] * point4D.x() + _arr[2][1] * point4D.y() + _arr[2][2] * point4D.z() + _arr[2][3] * point4D.w(),
|
|
||||||
_arr[3][0] * point4D.x() + _arr[3][1] * point4D.y() + _arr[3][2] * point4D.z() + _arr[3][3] * point4D.w()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 result;
|
|
||||||
|
|
||||||
result._arr[0][0] = 1.0;
|
|
||||||
result._arr[1][1] = 1.0;
|
|
||||||
result._arr[2][2] = 1.0;
|
|
||||||
result._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Constant(double value) {
|
|
||||||
Matrix4x4 result;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
for (int j = 0; j < 4; j++) {
|
|
||||||
result._arr[j][i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Zero() {
|
|
||||||
return Matrix4x4::Constant(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Scale(const Vec3D &factor) {
|
|
||||||
Matrix4x4 s{};
|
|
||||||
s._arr[0][0] = factor.x();
|
|
||||||
s._arr[1][1] = factor.y();
|
|
||||||
s._arr[2][2] = factor.z();
|
|
||||||
s._arr[3][3] = 1;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Translation(const Vec3D &v) {
|
|
||||||
Matrix4x4 t{};
|
|
||||||
|
|
||||||
t._arr[0][0] = 1.0;
|
|
||||||
t._arr[1][1] = 1.0;
|
|
||||||
t._arr[2][2] = 1.0;
|
|
||||||
t._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
t._arr[0][3] = v.x();
|
|
||||||
t._arr[1][3] = v.y();
|
|
||||||
t._arr[2][3] = v.z();
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::RotationX(double rx) {
|
|
||||||
Matrix4x4 Rx{};
|
|
||||||
|
|
||||||
double c = cos(rx), s = sin(rx);
|
|
||||||
|
|
||||||
Rx._arr[0][0] = 1.0;
|
|
||||||
|
|
||||||
Rx._arr[1][1] = c;
|
|
||||||
Rx._arr[1][2] = -s;
|
|
||||||
Rx._arr[2][1] = s;
|
|
||||||
Rx._arr[2][2] = c;
|
|
||||||
|
|
||||||
Rx._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return Rx;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::RotationY(double ry) {
|
|
||||||
Matrix4x4 Ry{};
|
|
||||||
|
|
||||||
double c = cos(ry), s = sin(ry);
|
|
||||||
|
|
||||||
Ry._arr[1][1] = 1.0;
|
|
||||||
|
|
||||||
Ry._arr[0][0] = c;
|
|
||||||
Ry._arr[0][2] = s;
|
|
||||||
Ry._arr[2][0] = -s;
|
|
||||||
Ry._arr[2][2] = c;
|
|
||||||
|
|
||||||
Ry._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return Ry;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::RotationZ(double rz) {
|
|
||||||
Matrix4x4 Rz{};
|
|
||||||
|
|
||||||
double c = cos(rz), s = sin(rz);
|
|
||||||
|
|
||||||
Rz._arr[2][2] = 1.0;
|
|
||||||
|
|
||||||
Rz._arr[0][0] = c;
|
|
||||||
Rz._arr[0][1] = -s;
|
|
||||||
Rz._arr[1][0] = s;
|
|
||||||
Rz._arr[1][1] = c;
|
|
||||||
|
|
||||||
Rz._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return Rz;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Rotation(const Vec3D &r) {
|
|
||||||
return RotationX(r.x()) * RotationY(r.y()) * RotationZ(r.z());
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Rotation(const Vec3D &v, double rv) {
|
|
||||||
Matrix4x4 Rv{};
|
|
||||||
Vec3D nv(v.normalized());
|
|
||||||
|
|
||||||
double c = cos(rv), s = sin(rv);
|
|
||||||
|
|
||||||
Rv._arr[0][0] = c + (1.0 - c) * nv.x() * nv.x();
|
|
||||||
Rv._arr[0][1] = (1.0 - c) * nv.x() * nv.y() - s * nv.z();
|
|
||||||
Rv._arr[0][2] = (1.0 - c) * nv.x() * nv.z() + s * nv.y();
|
|
||||||
|
|
||||||
Rv._arr[1][0] = (1.0 - c) * nv.x() * nv.y() + s * nv.z();
|
|
||||||
Rv._arr[1][1] = c + (1.0 - c) * nv.y() * nv.y();
|
|
||||||
Rv._arr[1][2] = (1.0 - c) * nv.y() * nv.z() - s * nv.x();
|
|
||||||
|
|
||||||
Rv._arr[2][0] = (1.0 - c) * nv.z() * nv.x() - s * nv.y();
|
|
||||||
Rv._arr[2][1] = (1.0 - c) * nv.z() * nv.y() + s * nv.x();
|
|
||||||
Rv._arr[2][2] = c + (1.0 - c) * nv.z() * nv.z();
|
|
||||||
|
|
||||||
Rv._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return Rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::Projection(double fov, double aspect, double ZNear, double ZFar) {
|
|
||||||
Matrix4x4 p{};
|
|
||||||
|
|
||||||
p._arr[0][0] = 1.0 / (tan(Consts::PI * fov * 0.5 / 180.0) * aspect);
|
|
||||||
p._arr[1][1] = 1.0 / tan(Consts::PI * fov * 0.5 / 180.0);
|
|
||||||
p._arr[2][2] = ZFar / (ZFar - ZNear);
|
|
||||||
p._arr[2][3] = -ZFar * ZNear / (ZFar - ZNear);
|
|
||||||
p._arr[3][2] = 1.0;
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::ScreenSpace(int width, int height) {
|
|
||||||
Matrix4x4 s{};
|
|
||||||
|
|
||||||
s._arr[0][0] = -0.5 * width;
|
|
||||||
s._arr[1][1] = -0.5 * height;
|
|
||||||
s._arr[2][2] = 1.0;
|
|
||||||
|
|
||||||
s._arr[0][3] = 0.5 * width;
|
|
||||||
s._arr[1][3] = 0.5 * height;
|
|
||||||
|
|
||||||
s._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
Matrix4x4 Matrix4x4::View(const Matrix4x4 &transformMatrix) {
|
|
||||||
Matrix4x4 V = Zero();
|
|
||||||
|
|
||||||
Vec3D left = transformMatrix.x();
|
|
||||||
Vec3D up = transformMatrix.y();
|
|
||||||
Vec3D lookAt = transformMatrix.z();
|
|
||||||
Vec3D eye = transformMatrix.w();
|
|
||||||
|
|
||||||
double left_sqrAbs = left.sqrAbs();
|
|
||||||
double up_sqrAbs = up.sqrAbs();
|
|
||||||
double lookAt_sqrAbs = lookAt.sqrAbs();
|
|
||||||
|
|
||||||
V._arr[0][0] = left.x()/left_sqrAbs;
|
|
||||||
V._arr[0][1] = left.y()/left_sqrAbs;
|
|
||||||
V._arr[0][2] = left.z()/left_sqrAbs;
|
|
||||||
V._arr[0][3] = -eye.dot(left)/left_sqrAbs;
|
|
||||||
|
|
||||||
V._arr[1][0] = up.x()/up_sqrAbs;
|
|
||||||
V._arr[1][1] = up.y()/up_sqrAbs;
|
|
||||||
V._arr[1][2] = up.z()/up_sqrAbs;
|
|
||||||
V._arr[1][3] = -eye.dot(up)/up_sqrAbs;
|
|
||||||
|
|
||||||
V._arr[2][0] = lookAt.x()/lookAt_sqrAbs;
|
|
||||||
V._arr[2][1] = lookAt.y()/lookAt_sqrAbs;
|
|
||||||
V._arr[2][2] = lookAt.z()/lookAt_sqrAbs;
|
|
||||||
V._arr[2][3] = -eye.dot(lookAt)/lookAt_sqrAbs;
|
|
||||||
|
|
||||||
V._arr[3][3] = 1.0;
|
|
||||||
|
|
||||||
return V;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Matrix4x4::x() const {
|
|
||||||
return Vec3D(_arr[0][0], _arr[1][0], _arr[2][0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Matrix4x4::y() const {
|
|
||||||
return Vec3D(_arr[0][1], _arr[1][1], _arr[2][1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Matrix4x4::z() const {
|
|
||||||
return Vec3D(_arr[0][2], _arr[1][2], _arr[2][2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Matrix4x4::w() const {
|
|
||||||
return Vec3D(_arr[0][3], _arr[1][3], _arr[2][3]);
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 12.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_MATRIX4X4_H
|
|
||||||
#define ENGINE_MATRIX4X4_H
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "Vec4D.h"
|
|
||||||
#include "Vec3D.h"
|
|
||||||
|
|
||||||
class Matrix4x4 final {
|
|
||||||
private:
|
|
||||||
std::array<std::array<double, 4>, 4> _arr{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Matrix4x4() = default;
|
|
||||||
|
|
||||||
Matrix4x4 &operator=(const Matrix4x4 &matrix4X4) = default;
|
|
||||||
|
|
||||||
[[nodiscard]] Matrix4x4 operator*(const Matrix4x4 &matrix4X4) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec4D operator*(const Vec4D &point4D) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D operator*(const Vec3D &vec) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D x() const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D y() const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D z() const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D w() const;
|
|
||||||
|
|
||||||
|
|
||||||
// Any useful matrix (static methods)
|
|
||||||
Matrix4x4 static Identity();
|
|
||||||
|
|
||||||
Matrix4x4 static Zero();
|
|
||||||
|
|
||||||
Matrix4x4 static Constant(double value);
|
|
||||||
|
|
||||||
Matrix4x4 static Scale(const Vec3D &factor);
|
|
||||||
|
|
||||||
Matrix4x4 static Translation(const Vec3D &v);
|
|
||||||
|
|
||||||
Matrix4x4 static Rotation(const Vec3D &r);
|
|
||||||
|
|
||||||
Matrix4x4 static RotationX(double rx);
|
|
||||||
|
|
||||||
Matrix4x4 static RotationY(double ry);
|
|
||||||
|
|
||||||
Matrix4x4 static RotationZ(double rz);
|
|
||||||
|
|
||||||
Matrix4x4 static Rotation(const Vec3D &v, double rv);
|
|
||||||
|
|
||||||
Matrix4x4 static View(const Matrix4x4 &transformMatrix);
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_MATRIX4X4_H
|
|
|
@ -1,72 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Plane.h"
|
|
||||||
|
|
||||||
Plane::Plane(const Triangle &tri) : _normal(tri.norm()), _point(tri[0]) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Plane::Plane(const Vec3D &N, const Vec3D &P) : _normal(N.normalized()), _point(P) {
|
|
||||||
}
|
|
||||||
|
|
||||||
double Plane::distance(const Vec3D &point) const {
|
|
||||||
return point.dot(_normal) - _point.dot(_normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<Vec3D, double> Plane::intersection(const Vec3D &start, const Vec3D &end) const {
|
|
||||||
double s_dot_n = start.dot(_normal);
|
|
||||||
double k = (s_dot_n - _point.dot(_normal)) / (s_dot_n - end.dot(_normal));
|
|
||||||
Vec3D res = start + (end - start) * k;
|
|
||||||
return std::make_pair(res, k);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Triangle> Plane::clip(const Triangle &tri) const {
|
|
||||||
|
|
||||||
std::vector<Triangle> result;
|
|
||||||
|
|
||||||
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++) {
|
|
||||||
if (distances[i] >= 0) {
|
|
||||||
insidePoints.emplace_back(tri[i]);
|
|
||||||
} else {
|
|
||||||
outsidePoints.emplace_back(tri[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insidePoints.size() == 1) {
|
|
||||||
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 (insidePoints.size() == 2) {
|
|
||||||
std::pair<Vec3D, double> intersect1 = intersection(insidePoints[0], outsidePoints[0]);
|
|
||||||
std::pair<Vec3D, double> intersect2 = intersection(insidePoints[1], outsidePoints[0]);
|
|
||||||
|
|
||||||
result.emplace_back(insidePoints[0].makePoint4D(),
|
|
||||||
intersect1.first.makePoint4D(),
|
|
||||||
insidePoints[1].makePoint4D(),
|
|
||||||
tri.color());
|
|
||||||
result.emplace_back(intersect1.first.makePoint4D(),
|
|
||||||
intersect2.first.makePoint4D(),
|
|
||||||
insidePoints[1].makePoint4D(),
|
|
||||||
tri.color());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insidePoints.size() == 3) {
|
|
||||||
result.emplace_back(tri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 19.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_PLANE_H
|
|
||||||
#define ENGINE_PLANE_H
|
|
||||||
|
|
||||||
#include "Vec4D.h"
|
|
||||||
#include "../Triangle.h"
|
|
||||||
|
|
||||||
class Plane final {
|
|
||||||
private:
|
|
||||||
const Vec3D _normal;
|
|
||||||
const Vec3D _point;
|
|
||||||
public:
|
|
||||||
Plane() = delete;
|
|
||||||
|
|
||||||
Plane(const Plane &plane) = default;
|
|
||||||
|
|
||||||
// You can define plane by defining the points in 3D space
|
|
||||||
explicit Plane(const Triangle &tri);
|
|
||||||
|
|
||||||
// Or by defining normal vector and one val laying on the plane
|
|
||||||
Plane(const Vec3D &N, const Vec3D &P);
|
|
||||||
|
|
||||||
[[nodiscard]] double distance(const Vec3D &point4D) const;
|
|
||||||
|
|
||||||
// Vec4D in space where line ('start' to 'end') intersects plain with normal vector '_n' and val '_p' lays on the plane
|
|
||||||
[[nodiscard]] std::pair<Vec3D, double> intersection(const Vec3D &start, const Vec3D &end) const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Triangle> clip(const Triangle &tri) const;
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D N() const { return _normal; }
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D P() const { return _point; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_PLANE_H
|
|
|
@ -1,77 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 10.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "Vec2D.h"
|
|
||||||
#include "../Consts.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 Vec4D &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 *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 *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 = sqrAbs();
|
|
||||||
if (vecAbs > Consts::EPS) {
|
|
||||||
return *this / sqrt(vecAbs);
|
|
||||||
} else {
|
|
||||||
return Vec2D(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double Vec2D::dot(const Vec2D &vec) const {
|
|
||||||
return vec.x() * x() + vec.y() * y();
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 10.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_VEC2D_H
|
|
||||||
#define SHOOTER_VEC2D_H
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "Vec4D.h"
|
|
||||||
|
|
||||||
class Vec2D final {
|
|
||||||
private:
|
|
||||||
std::array<double, 2> _arr_point{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Vec2D() = default;
|
|
||||||
|
|
||||||
Vec2D(const Vec2D &vec);
|
|
||||||
|
|
||||||
explicit Vec2D(const Vec4D &point4D);
|
|
||||||
|
|
||||||
explicit Vec2D(double x, double y = 0.0);
|
|
||||||
|
|
||||||
Vec2D &operator=(const Vec2D &) = default;
|
|
||||||
|
|
||||||
[[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
|
|
|
@ -1,96 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 09.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "Vec3D.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
Vec3D::Vec3D(const Vec3D &vec) {
|
|
||||||
_arr_point[0] = vec.x();
|
|
||||||
_arr_point[1] = vec.y();
|
|
||||||
_arr_point[2] = vec.z();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D::Vec3D(const Vec4D &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 *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 *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 = sqrAbs();
|
|
||||||
if (vecAbs > Consts::EPS) {
|
|
||||||
return *this / sqrt(vecAbs);
|
|
||||||
} else {
|
|
||||||
return Vec3D(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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()};
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Vec3D::makePoint4D() const {
|
|
||||||
return Vec4D(x(), y(), z(), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D Vec3D::Random() {
|
|
||||||
return Vec3D((double) rand() / RAND_MAX, (double) rand() / RAND_MAX, (double) rand() / RAND_MAX);
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 09.10.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_VEC3D_H
|
|
||||||
#define SHOOTER_VEC3D_H
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
#include "Vec4D.h"
|
|
||||||
|
|
||||||
class Vec3D final {
|
|
||||||
private:
|
|
||||||
std::array<double, 3> _arr_point{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Vec3D() = default;
|
|
||||||
|
|
||||||
Vec3D(const Vec3D &vec);
|
|
||||||
|
|
||||||
explicit Vec3D(const Vec4D &vec);
|
|
||||||
|
|
||||||
explicit Vec3D(double x, double y = 0.0, double z = 0.0);
|
|
||||||
|
|
||||||
Vec3D &operator=(const Vec3D &) = default;
|
|
||||||
|
|
||||||
[[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 Vec4D
|
|
||||||
[[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]] Vec4D makePoint4D() const;
|
|
||||||
|
|
||||||
static Vec3D Random();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_VEC3D_H
|
|
|
@ -1,74 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 12.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "Vec4D.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
Vec4D::Vec4D(double x, double y, double z, double w) {
|
|
||||||
_arr_point[0] = x;
|
|
||||||
_arr_point[1] = y;
|
|
||||||
_arr_point[2] = z;
|
|
||||||
_arr_point[3] = w;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D::Vec4D(const Vec4D &point4D) {
|
|
||||||
_arr_point[0] = point4D.x();
|
|
||||||
_arr_point[1] = point4D.y();
|
|
||||||
_arr_point[2] = point4D.z();
|
|
||||||
_arr_point[3] = point4D.w();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Vec4D Vec4D::operator-() const {
|
|
||||||
return Vec4D(-x(), -y(), -z(), -w());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vec4D::operator==(const Vec4D &point4D) const {
|
|
||||||
return (*this - point4D).sqrAbs() < Consts::EPS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Vec4D::operator!=(const Vec4D &point4D) const {
|
|
||||||
return !(*this == point4D);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operations with Vec4D
|
|
||||||
Vec4D Vec4D::operator+(const Vec4D &point4D) const {
|
|
||||||
return Vec4D(x() + point4D.x(), y() + point4D.y(), z() + point4D.z(), w() + point4D.w());
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Vec4D::operator-(const Vec4D &point4D) const {
|
|
||||||
return *this + -point4D;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Vec4D::operator*(double number) const {
|
|
||||||
return Vec4D(x() * number, y() * number, z() * number, w() * number);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Vec4D::operator/(double number) const {
|
|
||||||
if (std::abs(number) > Consts::EPS) {
|
|
||||||
return *this * (1.0 / number);
|
|
||||||
} else {
|
|
||||||
throw std::domain_error{"Vec4D::operator/(double number): division by zero"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other useful methods
|
|
||||||
double Vec4D::sqrAbs() const {
|
|
||||||
return x() * x() + y() * y() + z() * z() + w() * w();
|
|
||||||
}
|
|
||||||
|
|
||||||
double Vec4D::abs() const {
|
|
||||||
return sqrt(sqrAbs());
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec4D Vec4D::normalized() const {
|
|
||||||
double vecAbs = sqrAbs();
|
|
||||||
if (vecAbs > Consts::EPS) {
|
|
||||||
return *this / sqrt(vecAbs);
|
|
||||||
} else {
|
|
||||||
return Vec4D(1);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 12.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_POINT4D_H
|
|
||||||
#define ENGINE_POINT4D_H
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
|
|
||||||
class Vec4D final {
|
|
||||||
private:
|
|
||||||
std::array<double, 4> _arr_point{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Vec4D() = default;
|
|
||||||
|
|
||||||
Vec4D(const Vec4D &point4D);
|
|
||||||
|
|
||||||
explicit Vec4D(double x, double y = 0.0, double z = 0.0, double w = 0.0);
|
|
||||||
|
|
||||||
Vec4D &operator=(const Vec4D &point4D) = default;
|
|
||||||
|
|
||||||
[[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]] double w() const { return _arr_point[3]; }
|
|
||||||
|
|
||||||
[[nodiscard]] Vec4D operator-() const;
|
|
||||||
|
|
||||||
// Boolean operations
|
|
||||||
bool operator==(const Vec4D &point4D) const;
|
|
||||||
|
|
||||||
bool operator!=(const Vec4D &point4D) const;
|
|
||||||
|
|
||||||
// Operations with Vec4D
|
|
||||||
[[nodiscard]] Vec4D operator+(const Vec4D &point4D) const;
|
|
||||||
[[nodiscard]] Vec4D operator-(const Vec4D &point4D) const;
|
|
||||||
|
|
||||||
// Operations with numbers
|
|
||||||
[[nodiscard]] Vec4D operator*(double number) const;
|
|
||||||
[[nodiscard]] Vec4D operator/(double number) const;
|
|
||||||
|
|
||||||
// Other useful methods
|
|
||||||
[[nodiscard]] double sqrAbs() const; // Returns squared vector length
|
|
||||||
[[nodiscard]] double abs() const; // Returns vector length
|
|
||||||
[[nodiscard]] Vec4D normalized() const; // Returns normalized vector without changing
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_POINT4D_H
|
|
|
@ -1,130 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ClientUDP.h"
|
|
||||||
#include "MsgType.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
ClientUDP::ClientUDP() {
|
|
||||||
_socket.setTimeoutCallback([this](sf::Uint16 id) { return ClientUDP::timeout(id); });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientUDP::connected() const {
|
|
||||||
return _socket.ownId();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientUDP::isWorking() const {
|
|
||||||
return _working;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientUDP::connect(sf::IpAddress ip, sf::Uint16 port) {
|
|
||||||
_ip = ip;
|
|
||||||
_port = port;
|
|
||||||
sf::Packet packet;
|
|
||||||
packet << MsgType::Connect << Consts::NETWORK_VERSION;
|
|
||||||
_working = _socket.bind(0);
|
|
||||||
_socket.addConnection(_socket.serverId(), ip, port);
|
|
||||||
_socket.sendRely(packet, _socket.serverId());
|
|
||||||
|
|
||||||
Log::log("ClientUDP::connect(): connecting to the server...");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientUDP::update() {
|
|
||||||
if (!isWorking()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (isWorking() && process()) {}
|
|
||||||
|
|
||||||
// Send new client information to server
|
|
||||||
if (Time::time() - _lastBroadcast > 1.0 / Consts::NETWORK_WORLD_UPDATE_RATE && connected()) {
|
|
||||||
updatePacket();
|
|
||||||
_lastBroadcast = Time::time();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Socket update
|
|
||||||
_socket.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClientUDP::disconnect() {
|
|
||||||
sf::Packet packet;
|
|
||||||
packet << MsgType::Disconnect << _socket.ownId();
|
|
||||||
_socket.send(packet, _socket.serverId());
|
|
||||||
_socket.unbind();
|
|
||||||
_working = false;
|
|
||||||
|
|
||||||
Log::log("ClientUDP::disconnect(): disconnected from the server.");
|
|
||||||
processDisconnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClientUDP::timeout(sf::Uint16 id) {
|
|
||||||
Log::log("ClientUDP::timeout(): timeout from the server.");
|
|
||||||
|
|
||||||
if (id != _socket.serverId()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recive and process message.
|
|
||||||
// Returns true, if some message was received.
|
|
||||||
bool ClientUDP::process() {
|
|
||||||
sf::Packet packet;
|
|
||||||
sf::Uint16 senderId;
|
|
||||||
sf::Uint16 targetId;
|
|
||||||
|
|
||||||
MsgType type = _socket.receive(packet, senderId);
|
|
||||||
|
|
||||||
if (type == MsgType::Empty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!connected() && type != MsgType::Init) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
// here we process any operations based on msg type
|
|
||||||
case MsgType::Init:
|
|
||||||
packet >> targetId;
|
|
||||||
_socket.setId(targetId);
|
|
||||||
|
|
||||||
Log::log("ClientUDP::process(): client Id = " + std::to_string(targetId) + " connected.");
|
|
||||||
|
|
||||||
processInit(packet);
|
|
||||||
break;
|
|
||||||
case MsgType::ServerUpdate:
|
|
||||||
|
|
||||||
processUpdate(packet);
|
|
||||||
break;
|
|
||||||
case MsgType::NewClient:
|
|
||||||
|
|
||||||
Log::log("ClientUDP::process(): new client init...");
|
|
||||||
|
|
||||||
processNewClient(packet);
|
|
||||||
break;
|
|
||||||
case MsgType::Disconnect:
|
|
||||||
packet >> targetId;
|
|
||||||
if (targetId == _socket.ownId()) {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("ClientUDP::process(): client Id = " + std::to_string(targetId) + " disconnected from the server");
|
|
||||||
|
|
||||||
processDisconnect(targetId);
|
|
||||||
break;
|
|
||||||
case MsgType::Custom:
|
|
||||||
processCustomPacket(packet);
|
|
||||||
break;
|
|
||||||
case MsgType::Error:
|
|
||||||
Log::log("ClientUDP::process(): Error message");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log::log("ClientUDP::process(): unknown message type " + std::to_string(static_cast<int>(type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_CLIENTUDP_H
|
|
||||||
#define ENGINE_CLIENTUDP_H
|
|
||||||
|
|
||||||
#include "ReliableMsg.h"
|
|
||||||
#include "UDPSocket.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
class ClientUDP {
|
|
||||||
protected:
|
|
||||||
UDPSocket _socket;
|
|
||||||
double _lastBroadcast = -std::numeric_limits<double>::max();
|
|
||||||
bool _working = false;
|
|
||||||
sf::Uint16 _port{};
|
|
||||||
sf::IpAddress _ip{};
|
|
||||||
|
|
||||||
bool process();
|
|
||||||
|
|
||||||
bool timeout(sf::Uint16 id);
|
|
||||||
|
|
||||||
public:
|
|
||||||
// create new ClientUDP()
|
|
||||||
explicit ClientUDP();
|
|
||||||
|
|
||||||
[[nodiscard]] bool isWorking() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool connected() const;
|
|
||||||
|
|
||||||
void connect(sf::IpAddress ip, sf::Uint16 port);
|
|
||||||
|
|
||||||
void disconnect();
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
[[nodiscard]] sf::IpAddress serverIp() const { return _ip; }
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Uint16 serverPort() const { return _port; }
|
|
||||||
|
|
||||||
// virtual functions
|
|
||||||
virtual void updatePacket() {};
|
|
||||||
|
|
||||||
virtual void processInit(sf::Packet &packet) {};
|
|
||||||
|
|
||||||
virtual void processUpdate(sf::Packet &packet) {};
|
|
||||||
|
|
||||||
virtual void processNewClient(sf::Packet &packet) {};
|
|
||||||
|
|
||||||
virtual void processDisconnect(sf::Uint16 targetId) {};
|
|
||||||
|
|
||||||
virtual void processCustomPacket(sf::Packet &packet) {};
|
|
||||||
|
|
||||||
virtual void processDisconnected() {};
|
|
||||||
|
|
||||||
virtual ~ClientUDP() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_CLIENTUDP_H
|
|
|
@ -1,16 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "MsgType.h"
|
|
||||||
|
|
||||||
sf::Packet &operator<<(sf::Packet &packet, MsgType type) {
|
|
||||||
return packet << (sf::Uint16) type;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Packet &operator>>(sf::Packet &packet, MsgType &type) {
|
|
||||||
sf::Uint16 temp;
|
|
||||||
packet >> temp;
|
|
||||||
type = (MsgType) temp;
|
|
||||||
return packet;
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_MSGTYPE_H
|
|
||||||
#define ENGINE_MSGTYPE_H
|
|
||||||
|
|
||||||
#include <SFML/Network.hpp>
|
|
||||||
|
|
||||||
enum class MsgType {
|
|
||||||
// internal messages
|
|
||||||
Empty, // Empty message (there are no message)
|
|
||||||
Error, // Error message (something went wrong)
|
|
||||||
Confirm, // confirm receive
|
|
||||||
|
|
||||||
// external messages
|
|
||||||
Connect, // connection (client ---> server)
|
|
||||||
Disconnect, // disconnect (client <==> server)
|
|
||||||
Init, // initialization (client <--- server)
|
|
||||||
ServerUpdate, // update (client <--- server)
|
|
||||||
ClientUpdate, // update (client ---> server)
|
|
||||||
NewClient, // add new client (client <--- server)
|
|
||||||
|
|
||||||
// this is for higher level clients & servers
|
|
||||||
Custom,
|
|
||||||
};
|
|
||||||
|
|
||||||
sf::Packet &operator<<(sf::Packet &packet, MsgType type);
|
|
||||||
|
|
||||||
sf::Packet &operator>>(sf::Packet &packet, MsgType &type);
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_MSGTYPE_H
|
|
|
@ -1,26 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ReliableMsg.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
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) {}
|
|
||||||
|
|
||||||
bool ReliableMsg::trySend(sf::UdpSocket &socket) {
|
|
||||||
if (Time::time() - firstTry > Consts::NETWORK_TIMEOUT) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (Time::time() - lastTry > Consts::NETWORK_RELIABLE_RETRY_TIME) {
|
|
||||||
lastTry = Time::time();
|
|
||||||
socket.send(packet, address, port);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_RELIABLEMSG_H
|
|
||||||
#define ENGINE_RELIABLEMSG_H
|
|
||||||
|
|
||||||
#include <SFML/Network.hpp>
|
|
||||||
|
|
||||||
class ReliableMsg final {
|
|
||||||
private:
|
|
||||||
sf::Packet packet;
|
|
||||||
const sf::IpAddress address;
|
|
||||||
const sf::Uint16 port;
|
|
||||||
const double firstTry;
|
|
||||||
double lastTry;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ReliableMsg(sf::Packet &packet, sf::IpAddress address, sf::Uint16 port);
|
|
||||||
|
|
||||||
ReliableMsg(const ReliableMsg &msg);
|
|
||||||
|
|
||||||
bool trySend(sf::UdpSocket &socket);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_RELIABLEMSG_H
|
|
|
@ -1,132 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ServerUDP.h"
|
|
||||||
#include "MsgType.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
|
|
||||||
ServerUDP::ServerUDP() {
|
|
||||||
_socket.setTimeoutCallback([this](sf::Uint16 playerId) { return timeout(playerId); });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerUDP::isWorking() const {
|
|
||||||
return _working;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerUDP::start(sf::Uint16 port) {
|
|
||||||
_working = _socket.bind(port);
|
|
||||||
|
|
||||||
if (_working) {
|
|
||||||
Log::log("ServerUDP::start(): the server was successfully started.");
|
|
||||||
} else {
|
|
||||||
Log::log("ServerUDP::start(): failed to start the server.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return _working;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerUDP::update() {
|
|
||||||
if (!isWorking()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (process()) {}
|
|
||||||
|
|
||||||
// World state broadcast
|
|
||||||
if (Time::time() - _lastBroadcast > 1.0 / Consts::NETWORK_WORLD_UPDATE_RATE) {
|
|
||||||
broadcast();
|
|
||||||
_lastBroadcast = Time::time();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Socket update
|
|
||||||
_socket.update();
|
|
||||||
|
|
||||||
updateInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerUDP::stop() {
|
|
||||||
for (auto it = _clients.begin(); it != _clients.end();) {
|
|
||||||
sf::Packet packet;
|
|
||||||
packet << MsgType::Disconnect << *it;
|
|
||||||
_socket.send(packet, *it);
|
|
||||||
_clients.erase(it++);
|
|
||||||
}
|
|
||||||
|
|
||||||
_socket.unbind();
|
|
||||||
_working = false;
|
|
||||||
|
|
||||||
processStop();
|
|
||||||
|
|
||||||
Log::log("ServerUDP::stop(): the server was killed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ServerUDP::timeout(sf::Uint16 playerId) {
|
|
||||||
sf::Packet packet;
|
|
||||||
packet << MsgType::Disconnect << playerId;
|
|
||||||
|
|
||||||
_clients.erase(playerId);
|
|
||||||
|
|
||||||
for (auto client : _clients) {
|
|
||||||
_socket.sendRely(packet, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("ServerUDP::timeout(): client Id = " + std::to_string(playerId) + " disconnected due to timeout.");
|
|
||||||
processDisconnect(playerId);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recive and process message.
|
|
||||||
// Returns true, if some message was received.
|
|
||||||
bool ServerUDP::process() {
|
|
||||||
sf::Packet packet;
|
|
||||||
sf::Packet sendPacket;
|
|
||||||
sf::Uint16 senderId;
|
|
||||||
|
|
||||||
MsgType type = _socket.receive(packet, senderId);
|
|
||||||
|
|
||||||
if (type == MsgType::Empty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
// here we process any operations based on msg type
|
|
||||||
case MsgType::Connect:
|
|
||||||
Log::log("ServerUDP::process(): client Id = " + std::to_string(senderId) + " connecting...");
|
|
||||||
|
|
||||||
processConnect(senderId);
|
|
||||||
break;
|
|
||||||
case MsgType::ClientUpdate:
|
|
||||||
|
|
||||||
processClientUpdate(senderId, packet);
|
|
||||||
break;
|
|
||||||
case MsgType::Disconnect:
|
|
||||||
Log::log("ServerUDP::process(): client Id = " + std::to_string(senderId) + " disconnected.");
|
|
||||||
|
|
||||||
sendPacket << MsgType::Disconnect << senderId;
|
|
||||||
_clients.erase(senderId);
|
|
||||||
_socket.removeConnection(senderId);
|
|
||||||
for (auto client : _clients) {
|
|
||||||
_socket.sendRely(sendPacket, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
processDisconnect(senderId);
|
|
||||||
break;
|
|
||||||
case MsgType::Custom:
|
|
||||||
processCustomPacket(packet, senderId);
|
|
||||||
break;
|
|
||||||
case MsgType::Error:
|
|
||||||
Log::log("ServerUDP::process(): Error message");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log::log("ServerUDP::process(): message type " + std::to_string(static_cast<int>(type)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerUDP::~ServerUDP() {
|
|
||||||
stop();
|
|
||||||
_clients.clear();
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_SERVERUDP_H
|
|
||||||
#define ENGINE_SERVERUDP_H
|
|
||||||
|
|
||||||
#include "../World.h"
|
|
||||||
#include "../Camera.h"
|
|
||||||
#include "ReliableMsg.h"
|
|
||||||
#include "UDPSocket.h"
|
|
||||||
#include <memory>
|
|
||||||
#include <limits>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
class ServerUDP {
|
|
||||||
protected:
|
|
||||||
UDPSocket _socket;
|
|
||||||
double _lastBroadcast = -std::numeric_limits<double>::max();
|
|
||||||
bool _working = false;
|
|
||||||
|
|
||||||
bool process();
|
|
||||||
|
|
||||||
bool timeout(sf::Uint16 id);
|
|
||||||
|
|
||||||
std::set<sf::Uint16> _clients{};
|
|
||||||
public:
|
|
||||||
explicit ServerUDP();
|
|
||||||
|
|
||||||
[[nodiscard]] bool isWorking() const;
|
|
||||||
|
|
||||||
bool start(sf::Uint16 port);
|
|
||||||
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
virtual void updateInfo() {};
|
|
||||||
|
|
||||||
// virtual functions
|
|
||||||
virtual void broadcast() {};
|
|
||||||
|
|
||||||
// here you have to send Init message _back to 'targetId' and send NewClient message to all '_clients'
|
|
||||||
virtual void processConnect(sf::Uint16 senderId) {};
|
|
||||||
|
|
||||||
virtual void processClientUpdate(sf::Uint16 senderId, sf::Packet &packet) {};
|
|
||||||
|
|
||||||
virtual void processDisconnect(sf::Uint16 senderId) {};
|
|
||||||
|
|
||||||
virtual void processCustomPacket(sf::Packet &packet, sf::Uint16 senderId) {};
|
|
||||||
|
|
||||||
virtual void processStop() {};
|
|
||||||
|
|
||||||
virtual ~ServerUDP();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_SERVERUDP_H
|
|
|
@ -1,38 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "UDPConnection.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
UDPConnection::UDPConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port) : _id(id), _ip(ip), _port(port),
|
|
||||||
lastMsg(Time::time()) {}
|
|
||||||
|
|
||||||
sf::Uint16 UDPConnection::id() const {
|
|
||||||
return _id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sf::IpAddress &UDPConnection::ip() const {
|
|
||||||
return _ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Uint16 UDPConnection::port() const {
|
|
||||||
return _port;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UDPConnection::timeout() const {
|
|
||||||
return Time::time() - lastMsg > Consts::NETWORK_TIMEOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UDPConnection::same(sf::IpAddress &ip, sf::Uint16 port) const {
|
|
||||||
return _ip == ip && _port == port;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPConnection::update() {
|
|
||||||
lastMsg = Time::time();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPConnection::send(sf::UdpSocket &socket, sf::Packet &packet) {
|
|
||||||
socket.send(packet, _ip, _port);
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_UDPCONNECTION_H
|
|
||||||
#define ENGINE_UDPCONNECTION_H
|
|
||||||
|
|
||||||
#include <SFML/Network.hpp>
|
|
||||||
|
|
||||||
class UDPConnection final {
|
|
||||||
private:
|
|
||||||
const sf::Uint16 _id;
|
|
||||||
const sf::IpAddress _ip;
|
|
||||||
const sf::Uint16 _port;
|
|
||||||
double lastMsg;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit UDPConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port);
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Uint16 id() const;
|
|
||||||
|
|
||||||
[[nodiscard]] const sf::IpAddress &ip() const;
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Uint16 port() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool timeout() const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool same(sf::IpAddress &ip, sf::Uint16 port) const;
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
void send(sf::UdpSocket &socket, sf::Packet &packet);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_UDPCONNECTION_H
|
|
|
@ -1,185 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "UDPSocket.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket() : _ownId(0), _nextRelyMsgId(0) {
|
|
||||||
_socket.setBlocking(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::addConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port) {
|
|
||||||
_connections.insert({id, UDPConnection(id, ip, port)});
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::removeConnection(sf::Uint16 id) {
|
|
||||||
_connections.erase(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UDPSocket::bind(sf::Uint16 port) {
|
|
||||||
return _socket.bind(port) == sf::Socket::Status::Done;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::unbind() {
|
|
||||||
sf::Packet packet;
|
|
||||||
packet << MsgType::Disconnect << _ownId;
|
|
||||||
|
|
||||||
for (auto it = _connections.begin(); it != _connections.end();) {
|
|
||||||
send(packet, it->first);
|
|
||||||
_connections.erase(it++);
|
|
||||||
}
|
|
||||||
|
|
||||||
_relyPackets.clear();
|
|
||||||
_confirmTimes.clear();
|
|
||||||
_socket.unbind();
|
|
||||||
setId(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::setTimeoutCallback(std::function<bool(sf::Uint16)> callback) {
|
|
||||||
_timeoutCallback = std::move(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::setId(sf::Uint16 id) {
|
|
||||||
_ownId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Uint16 UDPSocket::ownId() const {
|
|
||||||
return _ownId;
|
|
||||||
}
|
|
||||||
|
|
||||||
sf::Uint16 UDPSocket::serverId() const {
|
|
||||||
return _serverId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::sendRely(const sf::Packet &packet, const sf::IpAddress &ip, sf::Uint16 port) {
|
|
||||||
sf::Packet finalPacket;
|
|
||||||
finalPacket << _ownId << true << _nextRelyMsgId;
|
|
||||||
finalPacket.append(packet.getData(), packet.getDataSize());
|
|
||||||
_relyPackets.insert({_nextRelyMsgId++, ReliableMsg(finalPacket, ip, port)});
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::sendRely(const sf::Packet &packet, sf::Uint16 id) {
|
|
||||||
if (!_connections.count(id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->sendRely(packet, _connections.at(id).ip(), _connections.at(id).port());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::send(const sf::Packet &packet, const sf::IpAddress &ip, sf::Uint16 port) {
|
|
||||||
sf::Packet finalPacket;
|
|
||||||
finalPacket << _ownId << false << _serverId;
|
|
||||||
finalPacket.append(packet.getData(), packet.getDataSize());
|
|
||||||
_socket.send(finalPacket, ip, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::send(const sf::Packet &packet, sf::Uint16 id) {
|
|
||||||
if (!_connections.count(id)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this->send(packet, _connections.at(id).ip(), _connections.at(id).port());
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDPSocket::update() {
|
|
||||||
for (auto it = _connections.begin(); it != _connections.end();) {
|
|
||||||
if (!it->second.timeout()) {
|
|
||||||
++it;
|
|
||||||
} else {
|
|
||||||
if (_timeoutCallback && !_timeoutCallback(it->first)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_connections.erase(it++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto it = _relyPackets.begin(); it != _relyPackets.end();) {
|
|
||||||
if (!it->second.trySend(_socket)) {
|
|
||||||
_relyPackets.erase(it++);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto it = _confirmTimes.begin(); it != _confirmTimes.end();) {
|
|
||||||
if (Time::time() - it->second > Consts::NETWORK_TIMEOUT) {
|
|
||||||
_confirmTimes.erase(it++);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MsgType UDPSocket::receive(sf::Packet &packet, sf::Uint16 &senderId) {
|
|
||||||
// Receive message
|
|
||||||
sf::IpAddress ip;
|
|
||||||
sf::Uint16 port;
|
|
||||||
|
|
||||||
packet.clear();
|
|
||||||
if (_socket.receive(packet, ip, port) != sf::Socket::Status::Done) {
|
|
||||||
return MsgType::Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read header
|
|
||||||
bool reply = false;
|
|
||||||
sf::Uint16 msgId = 0;
|
|
||||||
MsgType type;
|
|
||||||
senderId = 0;
|
|
||||||
if (!(packet >> senderId >> reply >> msgId >> type)) {
|
|
||||||
return MsgType::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_connections.count(senderId)) {
|
|
||||||
_connections.at(senderId).update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == MsgType::Confirm) {
|
|
||||||
_relyPackets.erase(msgId);
|
|
||||||
// you don't need this information on the highest levels
|
|
||||||
return MsgType::Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == MsgType::Connect) {
|
|
||||||
sf::Uint32 version = 0;
|
|
||||||
if (!(packet >> version) || version != Consts::NETWORK_VERSION) {
|
|
||||||
return MsgType::Error;
|
|
||||||
}
|
|
||||||
sf::Uint16 tmp;
|
|
||||||
for (tmp = Consts::NETWORK_MAX_CLIENTS; tmp >= 1; tmp--) {
|
|
||||||
if (!_connections.count(tmp)) {
|
|
||||||
senderId = tmp;
|
|
||||||
} else {
|
|
||||||
if (_connections.at(tmp).same(ip, port)) {
|
|
||||||
return MsgType::Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_connections.insert({senderId, UDPConnection(senderId, ip, port)});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_connections.count(senderId) || !_connections.at(senderId).same(ip, port) ||
|
|
||||||
reply && confirmed(msgId, senderId)) {
|
|
||||||
return MsgType::Error;
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UDPSocket::confirmed(sf::Uint16 msgId, sf::Uint16 senderId) {
|
|
||||||
sf::Packet confirmPacket;
|
|
||||||
confirmPacket << _ownId << false << msgId << MsgType::Confirm;
|
|
||||||
_connections.at(senderId).send(_socket, confirmPacket);
|
|
||||||
|
|
||||||
sf::Uint32 confirmId;
|
|
||||||
confirmId = (senderId << 16) | msgId;
|
|
||||||
|
|
||||||
bool repeat = _confirmTimes.count(confirmId);
|
|
||||||
_confirmTimes[confirmId] = Time::time();
|
|
||||||
|
|
||||||
return repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPSocket::~UDPSocket() {
|
|
||||||
unbind();
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 30.04.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_UDPSOCKET_H
|
|
||||||
#define ENGINE_UDPSOCKET_H
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <map>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "ReliableMsg.h"
|
|
||||||
#include "UDPConnection.h"
|
|
||||||
#include "MsgType.h"
|
|
||||||
|
|
||||||
class UDPSocket final {
|
|
||||||
private:
|
|
||||||
sf::UdpSocket _socket;
|
|
||||||
sf::Uint16 _nextRelyMsgId;
|
|
||||||
sf::Uint16 _ownId;
|
|
||||||
const sf::Uint16 _serverId = 0;
|
|
||||||
|
|
||||||
std::map<sf::Uint16, UDPConnection> _connections;
|
|
||||||
std::map<sf::Uint16, ReliableMsg> _relyPackets;
|
|
||||||
std::map<sf::Uint32, double> _confirmTimes;
|
|
||||||
std::function<bool(sf::Uint16)> _timeoutCallback;
|
|
||||||
|
|
||||||
bool confirmed(sf::Uint16 msgId, sf::Uint16 senderId);
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit UDPSocket();
|
|
||||||
|
|
||||||
bool bind(sf::Uint16 port);
|
|
||||||
|
|
||||||
void unbind();
|
|
||||||
|
|
||||||
void setTimeoutCallback(std::function<bool(sf::Uint16)> callback);
|
|
||||||
|
|
||||||
void addConnection(sf::Uint16 id, sf::IpAddress ip, sf::Uint16 port);
|
|
||||||
|
|
||||||
void removeConnection(sf::Uint16 id);
|
|
||||||
|
|
||||||
void setId(sf::Uint16 id);
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Uint16 ownId() const;
|
|
||||||
|
|
||||||
[[nodiscard]] sf::Uint16 serverId() const;
|
|
||||||
|
|
||||||
void send(const sf::Packet &packet, const sf::IpAddress &ip, sf::Uint16 port);
|
|
||||||
|
|
||||||
void send(const sf::Packet &packet, sf::Uint16 id);
|
|
||||||
|
|
||||||
void sendRely(const sf::Packet &packet, const sf::IpAddress &ip, sf::Uint16 port);
|
|
||||||
|
|
||||||
void sendRely(const sf::Packet &packet, sf::Uint16 id);
|
|
||||||
|
|
||||||
void update();
|
|
||||||
|
|
||||||
MsgType receive(sf::Packet &packet, sf::Uint16 &senderId);
|
|
||||||
|
|
||||||
~UDPSocket();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_UDPSOCKET_H
|
|
|
@ -1,87 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 04.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <set>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "HitBox.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
bool HitBox::Vec3DLess::operator()(const Vec3D& lhs, const Vec3D& rhs) const noexcept {
|
|
||||||
if (fabs(lhs.x() - rhs.x()) >= Consts::EPS)
|
|
||||||
return lhs.x() < rhs.x();
|
|
||||||
else if (fabs(lhs.y() - rhs.y()) >= Consts::EPS)
|
|
||||||
return lhs.y() < rhs.y();
|
|
||||||
else if (fabs(lhs.z() - rhs.z()) >= Consts::EPS)
|
|
||||||
return lhs.z() < rhs.z();
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
HitBox::HitBox(const Mesh& mesh, bool useSimpleBox) {
|
|
||||||
if (useSimpleBox) {
|
|
||||||
generateSimple(mesh);
|
|
||||||
} else {
|
|
||||||
generateDetailed(mesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HitBox::generateSimple(const Mesh &mesh) {
|
|
||||||
double maxX = -std::numeric_limits<double>::max();
|
|
||||||
double maxY = -std::numeric_limits<double>::max();
|
|
||||||
double maxZ = -std::numeric_limits<double>::max();
|
|
||||||
|
|
||||||
double minX = std::numeric_limits<double>::max();
|
|
||||||
double minY = std::numeric_limits<double>::max();
|
|
||||||
double minZ = std::numeric_limits<double>::max();
|
|
||||||
|
|
||||||
for(const auto& t : mesh.triangles()) {
|
|
||||||
for(int i = 0; i < 3; i++) {
|
|
||||||
auto point = Vec3D(t[i]);
|
|
||||||
if(point.x() > maxX) {
|
|
||||||
maxX = point.x();
|
|
||||||
}
|
|
||||||
if(point.y() > maxY) {
|
|
||||||
maxY = point.y();
|
|
||||||
}
|
|
||||||
if(point.z() > maxZ) {
|
|
||||||
maxZ = point.z();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(point.x() < minX) {
|
|
||||||
minX = point.x();
|
|
||||||
}
|
|
||||||
if(point.y() < minY) {
|
|
||||||
minY = point.y();
|
|
||||||
}
|
|
||||||
if(point.z() < minZ) {
|
|
||||||
minZ = point.z();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_hitBox.emplace_back(minX, minY, minZ);
|
|
||||||
_hitBox.emplace_back(minX, maxY, minZ);
|
|
||||||
_hitBox.emplace_back(maxX, minY, minZ);
|
|
||||||
_hitBox.emplace_back(maxX, maxY, minZ);
|
|
||||||
|
|
||||||
_hitBox.emplace_back(minX, minY, maxZ);
|
|
||||||
_hitBox.emplace_back(minX, maxY, maxZ);
|
|
||||||
_hitBox.emplace_back(maxX, minY, maxZ);
|
|
||||||
_hitBox.emplace_back(maxX, maxY, maxZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HitBox::generateDetailed(const Mesh &mesh) {
|
|
||||||
// we dont need to add the same points in hit box
|
|
||||||
std::set<Vec3D, HitBox::Vec3DLess> points;
|
|
||||||
|
|
||||||
for (const auto& t : mesh.triangles())
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
points.insert(Vec3D(t[i]));
|
|
||||||
|
|
||||||
_hitBox.reserve(points.size());
|
|
||||||
for (const auto& it : points)
|
|
||||||
_hitBox.push_back(it);
|
|
||||||
_hitBox.shrink_to_fit();
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 04.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_HITBOX_H
|
|
||||||
#define SHOOTER_HITBOX_H
|
|
||||||
|
|
||||||
#include "../Mesh.h"
|
|
||||||
|
|
||||||
class HitBox final {
|
|
||||||
private:
|
|
||||||
struct Vec3DLess {
|
|
||||||
bool operator()(const Vec3D& lhs, const Vec3D& rhs) const noexcept;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Vec3D> _hitBox;
|
|
||||||
|
|
||||||
void generateSimple(const Mesh &mesh);
|
|
||||||
void generateDetailed(const Mesh &mesh);
|
|
||||||
public:
|
|
||||||
HitBox() = default;
|
|
||||||
HitBox(const HitBox &hitBox) = default;
|
|
||||||
|
|
||||||
explicit HitBox(const Mesh &mesh, bool useSimpleBox = true);
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Vec3D>::iterator begin() { return _hitBox.begin(); }
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<Vec3D>::iterator end() { return _hitBox.end(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_HITBOX_H
|
|
|
@ -1,347 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 05.02.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "RigidBody.h"
|
|
||||||
#include "../utils/Log.h"
|
|
||||||
#include "../utils/Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
RigidBody::RigidBody(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scale, bool useSimpleBox) : Mesh(std::move(nameTag),
|
|
||||||
filename, scale),
|
|
||||||
_hitBox(*this, useSimpleBox) {
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidBody::RigidBody(const Mesh &mesh, bool useSimpleBox) : Mesh(mesh), _hitBox(mesh, useSimpleBox) {
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D RigidBody::_findFurthestPoint(const Vec3D &direction) {
|
|
||||||
Vec3D maxPoint{0, 0, 0};
|
|
||||||
|
|
||||||
double maxDistance = -std::numeric_limits<double>::max();
|
|
||||||
|
|
||||||
Vec3D transformedDirection = (invModel() * direction).normalized();
|
|
||||||
|
|
||||||
for(auto & it : _hitBox) {
|
|
||||||
double distance = it.dot(transformedDirection);
|
|
||||||
|
|
||||||
if (distance > maxDistance) {
|
|
||||||
maxDistance = distance;
|
|
||||||
maxPoint = it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return model() * maxPoint + position();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D RigidBody::_support(std::shared_ptr<RigidBody> obj, const Vec3D &direction) {
|
|
||||||
Vec3D p1 = _findFurthestPoint(direction);
|
|
||||||
Vec3D p2 = obj->_findFurthestPoint(-direction);
|
|
||||||
|
|
||||||
return p1 - p2;
|
|
||||||
}
|
|
||||||
|
|
||||||
NextSimplex RigidBody::_nextSimplex(const Simplex &points) {
|
|
||||||
switch (points.type()) {
|
|
||||||
case SimplexType::Line:
|
|
||||||
return _lineCase(points);
|
|
||||||
case SimplexType::Triangle:
|
|
||||||
return _triangleCase(points);
|
|
||||||
case SimplexType::Tetrahedron:
|
|
||||||
return _tetrahedronCase(points);
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw std::logic_error{"RigidBody::_nextSimplex: simplex is not Line, Triangle or Tetrahedron"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NextSimplex RigidBody::_lineCase(const Simplex &points) {
|
|
||||||
Simplex newPoints(points);
|
|
||||||
Vec3D newDirection;
|
|
||||||
|
|
||||||
Vec3D a = points[0];
|
|
||||||
Vec3D b = points[1];
|
|
||||||
|
|
||||||
Vec3D ab = b - a;
|
|
||||||
Vec3D ao = -a;
|
|
||||||
|
|
||||||
if (ab.dot(ao) > 0) {
|
|
||||||
newDirection = ab.cross(ao).cross(ab);
|
|
||||||
} else {
|
|
||||||
newPoints = Simplex{a};
|
|
||||||
newDirection = ao;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextSimplex{newPoints, newDirection, false};
|
|
||||||
}
|
|
||||||
|
|
||||||
NextSimplex RigidBody::_triangleCase(const Simplex &points) {
|
|
||||||
Simplex newPoints(points);
|
|
||||||
Vec3D newDirection;
|
|
||||||
|
|
||||||
Vec3D a = points[0];
|
|
||||||
Vec3D b = points[1];
|
|
||||||
Vec3D c = points[2];
|
|
||||||
|
|
||||||
Vec3D ab = b - a;
|
|
||||||
Vec3D ac = c - a;
|
|
||||||
Vec3D ao = -a;
|
|
||||||
|
|
||||||
Vec3D abc = ab.cross(ac);
|
|
||||||
|
|
||||||
if (abc.cross(ac).dot(ao) > 0) {
|
|
||||||
if (ac.dot(ao) > 0) {
|
|
||||||
newPoints = Simplex{a, c};
|
|
||||||
newDirection = ac.cross(ao).cross(ac);
|
|
||||||
} else {
|
|
||||||
return _lineCase(Simplex{a, b});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ab.cross(abc).dot(ao) > 0) {
|
|
||||||
return _lineCase(Simplex{a, b});
|
|
||||||
} else {
|
|
||||||
if (abc.dot(ao) > 0) {
|
|
||||||
newDirection = abc;
|
|
||||||
} else {
|
|
||||||
newPoints = Simplex{a, c, b};
|
|
||||||
newDirection = -abc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextSimplex{newPoints, newDirection, false};
|
|
||||||
}
|
|
||||||
|
|
||||||
NextSimplex RigidBody::_tetrahedronCase(const Simplex &points) {
|
|
||||||
Vec3D a = points[0];
|
|
||||||
Vec3D b = points[1];
|
|
||||||
Vec3D c = points[2];
|
|
||||||
Vec3D d = points[3];
|
|
||||||
|
|
||||||
Vec3D ab = b - a;
|
|
||||||
Vec3D ac = c - a;
|
|
||||||
Vec3D ad = d - a;
|
|
||||||
Vec3D ao = -a;
|
|
||||||
|
|
||||||
Vec3D abc = ab.cross(ac);
|
|
||||||
Vec3D acd = ac.cross(ad);
|
|
||||||
Vec3D adb = ad.cross(ab);
|
|
||||||
|
|
||||||
if (abc.dot(ao) > 0) {
|
|
||||||
return _triangleCase(Simplex{a, b, c});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (acd.dot(ao) > 0) {
|
|
||||||
return _triangleCase(Simplex{a, c, d});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adb.dot(ao) > 0) {
|
|
||||||
return _triangleCase(Simplex{a, d, b});
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextSimplex{points, Vec3D(), true};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<bool, Simplex> RigidBody::checkGJKCollision(std::shared_ptr<RigidBody> obj) {
|
|
||||||
// This is implementation of GJK algorithm for collision detection.
|
|
||||||
// It builds a simplex (a simplest shape that can select point in space) around
|
|
||||||
// zero for Minkowski Difference. Collision happend when zero point is inside.
|
|
||||||
// See references:
|
|
||||||
// https://www.youtube.com/watch?v=MDusDn8oTSE
|
|
||||||
// https://blog.winter.dev/2020/gjk-algorithm/
|
|
||||||
|
|
||||||
|
|
||||||
// Get initial support point in any direction
|
|
||||||
Vec3D support = _support(obj, Vec3D{1, 0, 0});
|
|
||||||
|
|
||||||
// Simplex is an array of points, max count is 4
|
|
||||||
Simplex points{};
|
|
||||||
points.push_front(support);
|
|
||||||
|
|
||||||
// New direction is towards the origin
|
|
||||||
Vec3D direction = -support;
|
|
||||||
|
|
||||||
size_t iters = 0;
|
|
||||||
while (iters++ < size() + obj->size()) {
|
|
||||||
support = _support(obj, direction);
|
|
||||||
|
|
||||||
if (support.dot(direction) <= 0) {
|
|
||||||
return std::make_pair(false, points); // no collision
|
|
||||||
}
|
|
||||||
|
|
||||||
points.push_front(support);
|
|
||||||
|
|
||||||
NextSimplex nextSimplex = _nextSimplex(points);
|
|
||||||
|
|
||||||
direction = nextSimplex.newDirection;
|
|
||||||
points = nextSimplex.newSimplex;
|
|
||||||
|
|
||||||
if (nextSimplex.finishSearching) {
|
|
||||||
if (obj->isCollider()) {
|
|
||||||
_inCollision = true;
|
|
||||||
}
|
|
||||||
return std::make_pair(true, points);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::make_pair(false, points);
|
|
||||||
}
|
|
||||||
|
|
||||||
CollisionPoint RigidBody::EPA(const Simplex &simplex, std::shared_ptr<RigidBody> obj) {
|
|
||||||
// This is implementation of EPA algorithm for solving collision.
|
|
||||||
// It uses a simplex from GJK around and expand it to the border.
|
|
||||||
// The goal is to calculate the nearest normal and the intersection depth.
|
|
||||||
// See references:
|
|
||||||
// https://www.youtube.com/watch?v=0XQ2FSz3EK8
|
|
||||||
// https://blog.winter.dev/2020/epa-algorithm/
|
|
||||||
|
|
||||||
std::vector<Vec3D> polytope(simplex.begin(), simplex.end());
|
|
||||||
std::vector<size_t> faces = {
|
|
||||||
0, 1, 2,
|
|
||||||
0, 3, 1,
|
|
||||||
0, 2, 3,
|
|
||||||
1, 3, 2
|
|
||||||
};
|
|
||||||
|
|
||||||
auto faceNormals = _getFaceNormals(polytope, faces);
|
|
||||||
std::vector<FaceNormal> normals = faceNormals.first;
|
|
||||||
size_t minFace = faceNormals.second;
|
|
||||||
|
|
||||||
Vec3D minNormal = normals[minFace].normal;
|
|
||||||
double minDistance = std::numeric_limits<double>::max();
|
|
||||||
|
|
||||||
size_t iters = 0;
|
|
||||||
while (minDistance == std::numeric_limits<double>::max() && iters++ < size() + obj->size()) {
|
|
||||||
minNormal = normals[minFace].normal;
|
|
||||||
minDistance = normals[minFace].distance;
|
|
||||||
|
|
||||||
Vec3D support = _support(obj, minNormal);
|
|
||||||
double sDistance = minNormal.dot(support);
|
|
||||||
|
|
||||||
if (std::abs(sDistance - minDistance) > Consts::EPA_EPS) {
|
|
||||||
minDistance = std::numeric_limits<double>::max();
|
|
||||||
std::vector<std::pair<size_t, size_t>> uniqueEdges;
|
|
||||||
|
|
||||||
size_t f = 0;
|
|
||||||
for (auto &normal : normals) {
|
|
||||||
if (normal.normal.dot(support) > 0) {
|
|
||||||
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 0, f + 1);
|
|
||||||
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 1, f + 2);
|
|
||||||
uniqueEdges = _addIfUniqueEdge(uniqueEdges, faces, f + 2, f + 0);
|
|
||||||
|
|
||||||
faces.erase(faces.begin() + f);
|
|
||||||
faces.erase(faces.begin() + f);
|
|
||||||
faces.erase(faces.begin() + f);
|
|
||||||
} else {
|
|
||||||
f += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<size_t> newFaces;
|
|
||||||
newFaces.reserve(uniqueEdges.size() * 3);
|
|
||||||
for (auto[edgeIndex1, edgeIndex2] : uniqueEdges) {
|
|
||||||
newFaces.push_back(edgeIndex1);
|
|
||||||
newFaces.push_back(edgeIndex2);
|
|
||||||
newFaces.push_back(polytope.size());
|
|
||||||
}
|
|
||||||
polytope.push_back(support);
|
|
||||||
|
|
||||||
faces.insert(faces.end(), newFaces.begin(), newFaces.end());
|
|
||||||
|
|
||||||
auto newFaceNormals = _getFaceNormals(polytope, faces);
|
|
||||||
|
|
||||||
normals = std::move(newFaceNormals.first);
|
|
||||||
minFace = newFaceNormals.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_collisionNormal = minNormal;
|
|
||||||
if (std::abs(minDistance - std::numeric_limits<double>::max()) < Consts::EPS) {
|
|
||||||
return CollisionPoint{minNormal, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
return CollisionPoint{minNormal, minDistance + Consts::EPA_EPS};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<std::vector<FaceNormal>, size_t>
|
|
||||||
RigidBody::_getFaceNormals(const std::vector<Vec3D> &polytope, const std::vector<size_t> &faces) {
|
|
||||||
std::vector<FaceNormal> normals;
|
|
||||||
normals.reserve(faces.size() / 3);
|
|
||||||
size_t nearestFaceIndex = 0;
|
|
||||||
double minDistance = std::numeric_limits<double>::max();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < faces.size(); i += 3) {
|
|
||||||
Vec3D a = polytope[faces[i + 0]];
|
|
||||||
Vec3D b = polytope[faces[i + 1]];
|
|
||||||
Vec3D c = polytope[faces[i + 2]];
|
|
||||||
|
|
||||||
Vec3D normal = (b - a).cross(c - a).normalized();
|
|
||||||
|
|
||||||
double distance = normal.dot(a);
|
|
||||||
|
|
||||||
if (distance < -Consts::EPS) {
|
|
||||||
normal = -normal;
|
|
||||||
distance *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
normals.emplace_back(FaceNormal{normal, distance});
|
|
||||||
|
|
||||||
if (distance < minDistance) {
|
|
||||||
nearestFaceIndex = i / 3;
|
|
||||||
minDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {normals, nearestFaceIndex};
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
|
|
||||||
std::vector<std::pair<size_t, size_t>> newEdges = edges;
|
|
||||||
|
|
||||||
// We are interested in reversed edge
|
|
||||||
// 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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return newEdges;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::solveCollision(const CollisionPoint &collision) {
|
|
||||||
|
|
||||||
Vec3D velocity_perpendicular = collision.normal * velocity().dot(collision.normal);
|
|
||||||
Vec3D velocity_parallel = velocity() - velocity_perpendicular;
|
|
||||||
|
|
||||||
setVelocity(velocity_parallel);
|
|
||||||
|
|
||||||
translate(-collision.normal * collision.depth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::updatePhysicsState() {
|
|
||||||
translate(_velocity * Time::deltaTime());
|
|
||||||
_velocity = _velocity + _acceleration * Time::deltaTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::setVelocity(const Vec3D &velocity) {
|
|
||||||
_velocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::addVelocity(const Vec3D &velocity) {
|
|
||||||
_velocity = _velocity + velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RigidBody::setAcceleration(const Vec3D &acceleration) {
|
|
||||||
_acceleration = acceleration;
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 05.02.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_RIGIDBODY_H
|
|
||||||
#define ENGINE_RIGIDBODY_H
|
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "../Triangle.h"
|
|
||||||
#include "Simplex.h"
|
|
||||||
#include "../Mesh.h"
|
|
||||||
#include "HitBox.h"
|
|
||||||
|
|
||||||
struct CollisionPoint final {
|
|
||||||
const Vec3D normal;
|
|
||||||
const double depth;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FaceNormal final {
|
|
||||||
const Vec3D normal;
|
|
||||||
const double distance;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NextSimplex final {
|
|
||||||
const Simplex newSimplex;
|
|
||||||
const Vec3D newDirection;
|
|
||||||
const bool finishSearching;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RigidBody : public Mesh {
|
|
||||||
private:
|
|
||||||
Vec3D _velocity{0, 0, 0};
|
|
||||||
Vec3D _acceleration{0, 0, 0};
|
|
||||||
|
|
||||||
bool _hasCollision = false;
|
|
||||||
bool _isCollider = true;
|
|
||||||
bool _isTrigger = false;
|
|
||||||
|
|
||||||
HitBox _hitBox{};
|
|
||||||
|
|
||||||
bool _inCollision = false;
|
|
||||||
Vec3D _collisionNormal{0, 0, 0};
|
|
||||||
|
|
||||||
Vec3D _findFurthestPoint(const Vec3D &direction);
|
|
||||||
Vec3D _support(std::shared_ptr<RigidBody> obj, const Vec3D &direction);
|
|
||||||
std::function<void(const ObjectNameTag &, std::shared_ptr<RigidBody>)> _collisionCallBack;
|
|
||||||
|
|
||||||
static NextSimplex _nextSimplex(const Simplex &points);
|
|
||||||
static NextSimplex _lineCase(const Simplex &points);
|
|
||||||
static NextSimplex _triangleCase(const Simplex &points);
|
|
||||||
static NextSimplex _tetrahedronCase(const Simplex &points);
|
|
||||||
|
|
||||||
static std::pair<std::vector<FaceNormal>, size_t>
|
|
||||||
_getFaceNormals(const std::vector<Vec3D> &polytope, const std::vector<size_t> &faces);
|
|
||||||
|
|
||||||
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);
|
|
||||||
public:
|
|
||||||
explicit RigidBody(ObjectNameTag nameTag) : Mesh(std::move(nameTag)) {};
|
|
||||||
RigidBody(const RigidBody &rigidBody) = default;
|
|
||||||
explicit RigidBody(const Mesh &mesh, bool useSimpleBox = true);
|
|
||||||
RigidBody(ObjectNameTag nameTag, const std::string &filename, const Vec3D &scale = Vec3D{1, 1, 1}, bool useSimpleBox = true);
|
|
||||||
|
|
||||||
[[nodiscard]] std::pair<bool, Simplex> checkGJKCollision(std::shared_ptr<RigidBody> obj);
|
|
||||||
[[nodiscard]] CollisionPoint EPA(const Simplex &simplex, std::shared_ptr<RigidBody> obj);
|
|
||||||
void solveCollision(const CollisionPoint &collision);
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D collisionNormal() const { return _collisionNormal; }
|
|
||||||
[[nodiscard]] bool hasCollision() const { return _hasCollision; }
|
|
||||||
[[nodiscard]] bool inCollision() const { return _inCollision; }
|
|
||||||
[[nodiscard]] bool isCollider() const { return _isCollider; }
|
|
||||||
[[nodiscard]] bool isTrigger() const { return _isTrigger; }
|
|
||||||
|
|
||||||
void setInCollision(bool c) { _inCollision = c; }
|
|
||||||
void setCollision(bool c) { _hasCollision = c; }
|
|
||||||
void setCollider(bool c) { _isCollider = c; }
|
|
||||||
void setTrigger(bool t) { _isTrigger = t; }
|
|
||||||
|
|
||||||
void updatePhysicsState();
|
|
||||||
|
|
||||||
void setVelocity(const Vec3D &velocity);
|
|
||||||
void addVelocity(const Vec3D &velocity);
|
|
||||||
void setAcceleration(const Vec3D &acceleration);
|
|
||||||
|
|
||||||
[[nodiscard]] Vec3D velocity() const { return _velocity; }
|
|
||||||
[[nodiscard]] Vec3D acceleration() const { return _acceleration; }
|
|
||||||
|
|
||||||
[[nodiscard]] const std::function<void(const ObjectNameTag &, std::shared_ptr<RigidBody>)> &
|
|
||||||
collisionCallBack() const { return _collisionCallBack; }
|
|
||||||
|
|
||||||
void setCollisionCallBack(const std::function<void(const ObjectNameTag &tag,
|
|
||||||
std::shared_ptr<RigidBody>)> &f) { _collisionCallBack = f; }
|
|
||||||
|
|
||||||
~RigidBody() override = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_RIGIDBODY_H
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 08.03.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_SIMPLEX_H
|
|
||||||
#define ENGINE_SIMPLEX_H
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "../math/Vec3D.h"
|
|
||||||
|
|
||||||
enum class SimplexType {
|
|
||||||
Zero,
|
|
||||||
Point,
|
|
||||||
Line,
|
|
||||||
Triangle,
|
|
||||||
Tetrahedron
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Simplex final {
|
|
||||||
private:
|
|
||||||
std::list<Vec3D> _points{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
Simplex() = default;
|
|
||||||
|
|
||||||
Simplex(std::initializer_list<Vec3D> list) {
|
|
||||||
for (const auto &v : list) {
|
|
||||||
_points.push_back(v);
|
|
||||||
if (_points.size() > 4) {
|
|
||||||
_points.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void push_front(const Vec3D &point) {
|
|
||||||
_points.push_front(point);
|
|
||||||
if (_points.size() > 4) {
|
|
||||||
_points.pop_back();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3D operator[](unsigned i) const {
|
|
||||||
auto it = _points.begin();
|
|
||||||
for (unsigned k = 0; k < i; k++) {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
return *it;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] unsigned size() const { return _points.size(); }
|
|
||||||
|
|
||||||
[[nodiscard]] auto begin() const { return _points.begin(); }
|
|
||||||
|
|
||||||
[[nodiscard]] auto end() const { return _points.end(); }
|
|
||||||
|
|
||||||
[[nodiscard]] SimplexType type() const { return static_cast<SimplexType>(_points.size()); }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_SIMPLEX_H
|
|
|
@ -1,28 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
|
|
||||||
#include <ctime>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "Log.h"
|
|
||||||
#include "Time.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
namespace Log {
|
|
||||||
void log(const std::string &message) {
|
|
||||||
if (Consts::USE_LOG_FILE) {
|
|
||||||
std::time_t const now_c = std::time(nullptr);
|
|
||||||
auto dt = std::put_time(std::localtime(&now_c), "%F %T");
|
|
||||||
|
|
||||||
std::fstream file("engine_log.txt", std::ios::out | std::ios::app);
|
|
||||||
file << dt << "\t" << message << " (" << Time::fps() << " fps)" << std::endl;
|
|
||||||
std::cout << dt << "\t" << message << " (" << Time::fps() << " fps)" << std::endl;
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 13.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_LOG_H
|
|
||||||
#define ENGINE_LOG_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace Log {
|
|
||||||
void log(const std::string &message);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_LOG_H
|
|
|
@ -1,41 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 22.01.2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ObjectController.h"
|
|
||||||
#include "Time.h"
|
|
||||||
#include "../math/Vec2D.h"
|
|
||||||
|
|
||||||
ObjectController::ObjectController(std::shared_ptr<Object> object,
|
|
||||||
std::shared_ptr<Mouse> mouse) :
|
|
||||||
_object(std::move(object)),
|
|
||||||
_mouse(std::move(mouse)){
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectController::update() {
|
|
||||||
// Left and right
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::A))
|
|
||||||
_object->translate(_object->left()*Time::deltaTime()*5.0);
|
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::D))
|
|
||||||
_object->translate(-_object->left()*Time::deltaTime()*5.0);
|
|
||||||
|
|
||||||
// Forward and backward
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::W))
|
|
||||||
_object->translate(_object->lookAt()*Time::deltaTime()*5.0);
|
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::S))
|
|
||||||
_object->translate(-_object->lookAt()*Time::deltaTime()*5.0);
|
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::LShift))
|
|
||||||
_object->translate(Vec3D{0.0, -Time::deltaTime()*5.0, 0});
|
|
||||||
|
|
||||||
if (Keyboard::isKeyPressed(sf::Keyboard::Space))
|
|
||||||
_object->translate(Vec3D{0.0, Time::deltaTime()*5.0, 0});
|
|
||||||
|
|
||||||
// Mouse movement
|
|
||||||
Vec2D disp = _mouse->getMouseDisplacement();
|
|
||||||
|
|
||||||
_object->rotate(Vec3D{0, -disp.x()/1000.0, 0});
|
|
||||||
_object->rotateLeft(disp.y()/1000.0);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 22.01.2022.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_OBJECTCONTROLLER_H
|
|
||||||
#define SHOOTER_OBJECTCONTROLLER_H
|
|
||||||
|
|
||||||
#include "../Object.h"
|
|
||||||
#include "../io/Keyboard.h"
|
|
||||||
#include "../io/Mouse.h"
|
|
||||||
|
|
||||||
class ObjectController {
|
|
||||||
private:
|
|
||||||
std::shared_ptr<Object> _object;
|
|
||||||
std::shared_ptr<Mouse> _mouse;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObjectController(std::shared_ptr<Object> object,
|
|
||||||
std::shared_ptr<Mouse> mouse);
|
|
||||||
|
|
||||||
void update();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //SHOOTER_OBJECTCONTROLLER_H
|
|
|
@ -1,252 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 09.05.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <sstream>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
|
||||||
#include "Log.h"
|
|
||||||
|
|
||||||
ResourceManager *ResourceManager::_instance = nullptr;
|
|
||||||
|
|
||||||
void ResourceManager::init() {
|
|
||||||
delete _instance;
|
|
||||||
_instance = new ResourceManager();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::init(): resource manager was initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<sf::Texture> ResourceManager::loadTexture(const std::string &filename) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If texture is already loaded - return pointer to it
|
|
||||||
auto it = _instance->_textures.find(filename);
|
|
||||||
if (it != _instance->_textures.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise - try to load it. If failure - return zero
|
|
||||||
std::shared_ptr<sf::Texture> texture(new sf::Texture);
|
|
||||||
if (!texture->loadFromFile(filename)) {
|
|
||||||
Log::log("ResourceManager::loadTexture: error with loading texture '" + filename + "'");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("ResourceManager::loadTexture: texture '" + filename + "' was loaded");
|
|
||||||
|
|
||||||
// If success - remember and return texture pointer
|
|
||||||
texture->setRepeated(true);
|
|
||||||
_instance->_textures.emplace(filename, texture);
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<sf::SoundBuffer> ResourceManager::loadSoundBuffer(const std::string &filename) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If sound buffer is already loaded - return pointer to it
|
|
||||||
auto it = _instance->_soundBuffers.find(filename);
|
|
||||||
if (it != _instance->_soundBuffers.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise - try to load it. If failure - return zero
|
|
||||||
std::shared_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer);
|
|
||||||
if (!soundBuffer->loadFromFile(filename)) {
|
|
||||||
Log::log("ResourceManager::loadSoundBuffer: error with loading sound buffer '" + filename + "'");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("ResourceManager::loadSoundBuffer: sound buffer '" + filename + "' was loaded");
|
|
||||||
|
|
||||||
// If success - remember and return sound pointer
|
|
||||||
_instance->_soundBuffers.emplace(filename, soundBuffer);
|
|
||||||
|
|
||||||
return soundBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<sf::Font> ResourceManager::loadFont(const std::string &filename) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If font is already loaded - return pointer to it
|
|
||||||
auto it = _instance->_fonts.find(filename);
|
|
||||||
if (it != _instance->_fonts.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise - try to load it. If failure - return zero
|
|
||||||
std::shared_ptr<sf::Font> font(new sf::Font);
|
|
||||||
if (!font->loadFromFile(filename)) {
|
|
||||||
Log::log("ResourceManager::loadFont: error with loading font: '" + filename + "'");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log::log("ResourceManager::loadFont: font '" + filename + "' was loaded");
|
|
||||||
|
|
||||||
// If success - remember and return font pointer
|
|
||||||
_instance->_fonts.emplace(filename, font);
|
|
||||||
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Mesh>> ResourceManager::loadObjects(const std::string &filename) {
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Mesh>> objects{};
|
|
||||||
std::map<std::string, sf::Color> maters{};
|
|
||||||
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// If objects is already loaded - return pointer to it
|
|
||||||
auto it = _instance->_objects.find(filename);
|
|
||||||
if (it != _instance->_objects.end()) {
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ifstream file(filename);
|
|
||||||
if (!file.is_open()) {
|
|
||||||
Log::log("Mesh::LoadObjects(): cannot load file from '" + filename + "'");
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Vec4D> verts{};
|
|
||||||
std::vector<Triangle> tris{};
|
|
||||||
sf::Color currentColor = sf::Color(255, 245, 194, 255);
|
|
||||||
|
|
||||||
while (!file.eof()) {
|
|
||||||
char line[128];
|
|
||||||
file.getline(line, 128);
|
|
||||||
|
|
||||||
std::stringstream s;
|
|
||||||
s << line;
|
|
||||||
|
|
||||||
char junk;
|
|
||||||
if (line[0] == 'o') {
|
|
||||||
if (!tris.empty())
|
|
||||||
objects.push_back(
|
|
||||||
std::make_shared<Mesh>(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), tris));
|
|
||||||
tris.clear();
|
|
||||||
}
|
|
||||||
if (line[0] == 'v') {
|
|
||||||
double x, y, z;
|
|
||||||
s >> junk >> x >> y >> z;
|
|
||||||
verts.emplace_back(x, y, z, 1.0);
|
|
||||||
}
|
|
||||||
if (line[0] == 'g') {
|
|
||||||
std::string matInfo;
|
|
||||||
s >> junk >> matInfo;
|
|
||||||
std::string colorName = matInfo.substr(matInfo.size() - 3, 3);
|
|
||||||
currentColor = maters[matInfo.substr(matInfo.size() - 3, 3)];
|
|
||||||
}
|
|
||||||
if (line[0] == 'f') {
|
|
||||||
int f[3];
|
|
||||||
s >> junk >> f[0] >> f[1] >> f[2];
|
|
||||||
tris.emplace_back(verts[f[0] - 1], verts[f[1] - 1], verts[f[2] - 1], currentColor);
|
|
||||||
}
|
|
||||||
if (line[0] == 'm') {
|
|
||||||
int color[4];
|
|
||||||
std::string matName;
|
|
||||||
|
|
||||||
s >> junk >> matName >> color[0] >> color[1] >> color[2] >> color[3];
|
|
||||||
maters.insert({matName, sf::Color(color[0], color[1], color[2], color[3])});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tris.empty()) {
|
|
||||||
objects.push_back(
|
|
||||||
std::make_shared<Mesh>(ObjectNameTag(filename + "_temp_obj_" + std::to_string(objects.size())), tris));
|
|
||||||
}
|
|
||||||
tris.clear();
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
Log::log("Mesh::LoadObjects(): obj '" + filename + "' was loaded");
|
|
||||||
|
|
||||||
// If success - remember and return vector of objects pointer
|
|
||||||
_instance->_objects.emplace(filename, objects);
|
|
||||||
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::unloadTextures() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int texturesCounter = _instance->_textures.size();
|
|
||||||
for (auto &_texture : _instance->_textures) {
|
|
||||||
_texture.second.reset();
|
|
||||||
}
|
|
||||||
_instance->_textures.clear();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::unloadTextures(): all " + std::to_string(texturesCounter) + " textures was unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::unloadSoundBuffers() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int soundBuffersCounter = _instance->_soundBuffers.size();
|
|
||||||
for (auto &_soundBuffer : _instance->_soundBuffers) {
|
|
||||||
_soundBuffer.second.reset();
|
|
||||||
}
|
|
||||||
_instance->_soundBuffers.clear();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::unloadSoundBuffers(): all " + std::to_string(soundBuffersCounter) +
|
|
||||||
" soundBuffers was unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::unloadFonts() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fontsCounter = _instance->_fonts.size();
|
|
||||||
for (auto &_font : _instance->_fonts) {
|
|
||||||
_font.second.reset();
|
|
||||||
}
|
|
||||||
_instance->_fonts.clear();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::unloadFonts(): all " + std::to_string(fontsCounter) + " fonts was unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::unloadObjects() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int objCounter = _instance->_objects.size();
|
|
||||||
_instance->_objects.clear();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::unloadObjects(): all " + std::to_string(objCounter) + " objects was unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::unloadAllResources() {
|
|
||||||
unloadTextures();
|
|
||||||
unloadSoundBuffers();
|
|
||||||
unloadFonts();
|
|
||||||
unloadObjects();
|
|
||||||
|
|
||||||
Log::log("ResourceManager::unloadAllResources(): all resources was unloaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResourceManager::free() {
|
|
||||||
unloadAllResources();
|
|
||||||
|
|
||||||
delete _instance;
|
|
||||||
_instance = nullptr;
|
|
||||||
|
|
||||||
Log::log("ResourceManager::free(): pointer to 'ResourceManager' was freed");
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Neirokan on 09.05.2020
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_RESOURCEMANAGER_H
|
|
||||||
#define ENGINE_RESOURCEMANAGER_H
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <SFML/Graphics.hpp>
|
|
||||||
#include <SFML/Audio.hpp>
|
|
||||||
|
|
||||||
#include "../Mesh.h"
|
|
||||||
|
|
||||||
class ResourceManager final {
|
|
||||||
private:
|
|
||||||
std::map<std::string, std::shared_ptr<sf::Texture>> _textures;
|
|
||||||
std::map<std::string, std::shared_ptr<sf::Font>> _fonts;
|
|
||||||
std::map<std::string, std::shared_ptr<sf::SoundBuffer>> _soundBuffers;
|
|
||||||
std::map<std::string, std::vector<std::shared_ptr<Mesh>>> _objects;
|
|
||||||
|
|
||||||
static ResourceManager *_instance;
|
|
||||||
|
|
||||||
ResourceManager() = default;
|
|
||||||
|
|
||||||
// Unloads all currently loaded textures.
|
|
||||||
static void unloadObjects();
|
|
||||||
|
|
||||||
static void unloadTextures();
|
|
||||||
|
|
||||||
static void unloadSoundBuffers();
|
|
||||||
|
|
||||||
static void unloadFonts();
|
|
||||||
|
|
||||||
public:
|
|
||||||
ResourceManager(const ResourceManager &) = delete;
|
|
||||||
|
|
||||||
ResourceManager &operator=(ResourceManager &) = delete;
|
|
||||||
|
|
||||||
static void unloadAllResources();
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
|
|
||||||
static void free();
|
|
||||||
|
|
||||||
// Try to load texture from file.
|
|
||||||
// If success returns pointer to texture.
|
|
||||||
// Otherwise returns nullptr.
|
|
||||||
static std::vector<std::shared_ptr<Mesh>> loadObjects(const std::string &filename);
|
|
||||||
|
|
||||||
static std::shared_ptr<sf::Texture> loadTexture(const std::string &filename);
|
|
||||||
|
|
||||||
static std::shared_ptr<sf::Font> loadFont(const std::string &filename);
|
|
||||||
|
|
||||||
static std::shared_ptr<sf::SoundBuffer> loadSoundBuffer(const std::string &filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //PSEUDO3DENGINE_RESOURCEMANAGER_H
|
|
|
@ -1,115 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 11.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Time.h"
|
|
||||||
#include "Log.h"
|
|
||||||
#include "../Consts.h"
|
|
||||||
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
Time *Time::_instance = nullptr;
|
|
||||||
|
|
||||||
void Time::init() {
|
|
||||||
delete _instance;
|
|
||||||
_instance = new Time();
|
|
||||||
|
|
||||||
Log::log("Time::init(): time was initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
double Time::time() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance->_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Time::deltaTime() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _instance->_deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Time::update() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
high_resolution_clock::time_point t = high_resolution_clock::now();
|
|
||||||
|
|
||||||
_instance->_deltaTime = duration<double>(t - _instance->_last).count();
|
|
||||||
_instance->_time = duration<double>(t - _instance->_start).count();
|
|
||||||
// in case when fps < 10 it is useful to decrease _deltaTime (to avoid collision problems)
|
|
||||||
if (_instance->_deltaTime > Consts::LARGEST_TIME_STEP) {
|
|
||||||
_instance->_deltaTime = Consts::LARGEST_TIME_STEP;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance->_last = t;
|
|
||||||
|
|
||||||
if (_instance->_deltaTime > 10) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_instance->_fpsCounter++;
|
|
||||||
if (t - _instance->_fpsStart > _instance->_fpsCountTime) {
|
|
||||||
_instance->_lastFps = _instance->_fpsCounter / duration<double>(t - _instance->_fpsStart).count();
|
|
||||||
_instance->_fpsCounter = 0;
|
|
||||||
_instance->_fpsStart = t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Time::fps() {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// Cast is faster than floor and has the same behavior for positive numbers
|
|
||||||
return static_cast<int>(_instance->_lastFps);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Time::startTimer(const std::string &timerName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_instance->_timers.insert({timerName, Timer()});
|
|
||||||
_instance->_timers[timerName].start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Time::stopTimer(const std::string &timerName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(_instance->_timers.count(timerName) > 0) {
|
|
||||||
_instance->_timers[timerName].stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double Time::elapsedTimerMilliseconds(const std::string &timerName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(_instance->_timers.count(timerName) > 0) {
|
|
||||||
return _instance->_timers[timerName].elapsedMilliseconds();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Time::elapsedTimerSeconds(const std::string &timerName) {
|
|
||||||
if (_instance == nullptr) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(_instance->_timers.count(timerName) > 0) {
|
|
||||||
return _instance->_timers[timerName].elapsedSeconds();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Time::free() {
|
|
||||||
delete _instance;
|
|
||||||
_instance = nullptr;
|
|
||||||
|
|
||||||
Log::log("Time::free(): pointer to 'Time' was freed");
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 11.01.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef ENGINE_TIME_H
|
|
||||||
#define ENGINE_TIME_H
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "Timer.h"
|
|
||||||
|
|
||||||
class Time final {
|
|
||||||
private:
|
|
||||||
std::map<std::string, Timer> _timers;
|
|
||||||
|
|
||||||
// High precision time
|
|
||||||
std::chrono::high_resolution_clock::time_point _start = std::chrono::high_resolution_clock::now();
|
|
||||||
std::chrono::high_resolution_clock::time_point _last = _start;
|
|
||||||
|
|
||||||
// FPS counter
|
|
||||||
std::chrono::high_resolution_clock::time_point _fpsStart{};
|
|
||||||
std::chrono::milliseconds _fpsCountTime = std::chrono::milliseconds(1000);
|
|
||||||
int _fpsCounter = 0;
|
|
||||||
double _lastFps = 0;
|
|
||||||
|
|
||||||
// Compatibility
|
|
||||||
double _time = 0;
|
|
||||||
double _deltaTime = 0;
|
|
||||||
|
|
||||||
static Time *_instance;
|
|
||||||
|
|
||||||
Time() = default;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Time(const Time &) = delete;
|
|
||||||
|
|
||||||
Time &operator=(Time &) = delete;
|
|
||||||
|
|
||||||
static int fps();
|
|
||||||
|
|
||||||
static double time();
|
|
||||||
|
|
||||||
static double deltaTime();
|
|
||||||
|
|
||||||
static void update();
|
|
||||||
|
|
||||||
static void init();
|
|
||||||
|
|
||||||
static void free();
|
|
||||||
|
|
||||||
static void startTimer(const std::string& timerName);
|
|
||||||
static void stopTimer(const std::string& timerName);
|
|
||||||
|
|
||||||
[[nodiscard]] static double elapsedTimerMilliseconds(const std::string& timerName);
|
|
||||||
[[nodiscard]] static double elapsedTimerSeconds(const std::string& timerName);
|
|
||||||
|
|
||||||
[[nodiscard]] static std::map<std::string, Timer> const & timers() { return _instance->_timers; }
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //INC_3DZAVR_TIME_H
|
|
|
@ -1,33 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 03.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Timer.h"
|
|
||||||
|
|
||||||
using namespace std::chrono;
|
|
||||||
|
|
||||||
void Timer::start() {
|
|
||||||
_startTime = high_resolution_clock::now();
|
|
||||||
_isRunning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Timer::stop() {
|
|
||||||
_endTime = high_resolution_clock::now();
|
|
||||||
_isRunning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Timer::elapsedMilliseconds() const {
|
|
||||||
return elapsedSeconds()*1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
double Timer::elapsedSeconds() const {
|
|
||||||
high_resolution_clock::time_point endTime;
|
|
||||||
|
|
||||||
if(_isRunning) {
|
|
||||||
endTime = high_resolution_clock::now();
|
|
||||||
} else {
|
|
||||||
endTime = _endTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return duration<double>(endTime - _startTime).count();
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
//
|
|
||||||
// Created by Иван Ильин on 03.11.2021.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef SHOOTER_TIMER_H
|
|
||||||
#define SHOOTER_TIMER_H
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <ctime>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
class Timer {
|
|
||||||
private:
|
|
||||||
std::chrono::high_resolution_clock::time_point _startTime;
|
|
||||||
std::chrono::high_resolution_clock::time_point _endTime;
|
|
||||||
bool _isRunning = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void start();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
[[nodiscard]] double elapsedMilliseconds() const;
|
|
||||||
[[nodiscard]] double elapsedSeconds() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif //SHOOTER_TIMER_H
|
|
|
@ -5,10 +5,10 @@
|
||||||
#include "ShooterClient.h"
|
#include "ShooterClient.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "../engine/utils/Log.h"
|
#include "../3dzavr/engine/utils/Log.h"
|
||||||
#include "../engine/animation/Timeline.h"
|
#include "../3dzavr/engine/animation/Timeline.h"
|
||||||
#include "ShooterMsgType.h"
|
#include "ShooterMsgType.h"
|
||||||
#include "../engine/animation/Animations.h"
|
#include "../3dzavr/engine/animation/Animations.h"
|
||||||
|
|
||||||
void ShooterClient::updatePacket() {
|
void ShooterClient::updatePacket() {
|
||||||
sf::Packet packet;
|
sf::Packet packet;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef SHOOTER_SHOOTERCLIENT_H
|
#ifndef SHOOTER_SHOOTERCLIENT_H
|
||||||
#define SHOOTER_SHOOTERCLIENT_H
|
#define SHOOTER_SHOOTERCLIENT_H
|
||||||
|
|
||||||
#include "../engine/network/ClientUDP.h"
|
#include "../3dzavr/engine/network/ClientUDP.h"
|
||||||
#include "../player/Player.h"
|
#include "../player/Player.h"
|
||||||
|
|
||||||
class ShooterClient final : public ClientUDP {
|
class ShooterClient final : public ClientUDP {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "ShooterServer.h"
|
#include "ShooterServer.h"
|
||||||
#include "../engine/utils/Log.h"
|
#include "../3dzavr/engine/utils/Log.h"
|
||||||
#include "ShooterMsgType.h"
|
#include "ShooterMsgType.h"
|
||||||
|
|
||||||
void ShooterServer::broadcast() {
|
void ShooterServer::broadcast() {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef SHOOTER_SHOOTERSERVER_H
|
#ifndef SHOOTER_SHOOTERSERVER_H
|
||||||
#define SHOOTER_SHOOTERSERVER_H
|
#define SHOOTER_SHOOTERSERVER_H
|
||||||
|
|
||||||
#include "../engine/network/ServerUDP.h"
|
#include "../3dzavr/engine/network/ServerUDP.h"
|
||||||
#include "../player/Player.h"
|
#include "../player/Player.h"
|
||||||
|
|
||||||
struct BonusInfo final {
|
struct BonusInfo final {
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "../engine/io/Screen.h"
|
#include "../3dzavr/engine/io/Screen.h"
|
||||||
#include "../engine/utils/Log.h"
|
#include "../3dzavr/engine/utils/Log.h"
|
||||||
#include "../engine/animation/Animations.h"
|
#include "../3dzavr/engine/animation/Animations.h"
|
||||||
|
|
||||||
Player::Player(ObjectNameTag name, const std::string &filename, const Vec3D &scale) : RigidBody(std::move(name), filename, scale) {
|
Player::Player(ObjectNameTag name, const std::string &filename, const Vec3D &scale) : RigidBody(std::move(name), filename, scale) {
|
||||||
setAcceleration(Vec3D{0, -ShooterConsts::GRAVITY, 0});
|
setAcceleration(Vec3D{0, -ShooterConsts::GRAVITY, 0});
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
|
|
||||||
#include <SFML/Audio/Sound.hpp>
|
#include <SFML/Audio/Sound.hpp>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "../engine/utils/ResourceManager.h"
|
#include "../3dzavr/engine/utils/ResourceManager.h"
|
||||||
#include "../engine/Camera.h"
|
#include "../3dzavr/engine/Camera.h"
|
||||||
#include "../engine/World.h"
|
#include "../3dzavr/engine/World.h"
|
||||||
#include "../weapon/Ak47.h"
|
#include "../weapon/Ak47.h"
|
||||||
#include "../weapon/Shotgun.h"
|
#include "../weapon/Shotgun.h"
|
||||||
#include "../weapon/Gun.h"
|
#include "../weapon/Gun.h"
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "PlayerController.h"
|
#include "PlayerController.h"
|
||||||
#include "../engine/utils/Log.h"
|
#include "../3dzavr/engine/utils/Log.h"
|
||||||
#include "../engine/animation/Animations.h"
|
#include "../3dzavr/engine/animation/Animations.h"
|
||||||
|
|
||||||
PlayerController::PlayerController(std::shared_ptr<Player> player,
|
PlayerController::PlayerController(std::shared_ptr<Player> player,
|
||||||
std::shared_ptr<Keyboard> keyboard,
|
std::shared_ptr<Keyboard> keyboard,
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
#define SHOOTER_PLAYERCONTROLLER_H
|
#define SHOOTER_PLAYERCONTROLLER_H
|
||||||
|
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "../engine/io/Keyboard.h"
|
#include "../3dzavr/engine/io/Keyboard.h"
|
||||||
#include "../engine/io/Mouse.h"
|
#include "../3dzavr/engine/io/Mouse.h"
|
||||||
|
|
||||||
class PlayerController final {
|
class PlayerController final {
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#define SHOOTER_GUN_H
|
#define SHOOTER_GUN_H
|
||||||
|
|
||||||
#include "Weapon.h"
|
#include "Weapon.h"
|
||||||
#include "../engine/utils/ResourceManager.h"
|
#include "../3dzavr/engine/utils/ResourceManager.h"
|
||||||
#include "../ShooterConsts.h"
|
#include "../ShooterConsts.h"
|
||||||
|
|
||||||
class Gun final : public Weapon {
|
class Gun final : public Weapon {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue