Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added multi-monitor support #57

Merged
merged 3 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions content/setting/setting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ Physic:
GravityX: 0
GravityY: 9.81
Bounciness: 0.7 # [0, 1] : 0 no bounciness, 1 full energie restitution
ContinusCollisionMaxVelocity: 40 # min 0
FootBasasementWidth: 4 # min 2
FootBasasementHeight: 2 # min 2
ContinuousCollisionMaxVelocity: 40 # min 0
FootBasementWidth: 4 # min 2
FootBasementHeight: 2 # min 2
CollisionPixelRatioStopMovement: 0.3 # min 0, max 1. Ratio of pixel with collision to detect a real collision
IsGroundedDetection: 1.0 # min 0
InputReleaseImpulse: 3.0 # min 0
GamePlay:
CoyoteTimeCursorMovement: 0.1 # min 0
Window:
ShowFrameBufferBackground: false
UseFowardWindow: true
UseForwardWindow: true
ShowWindow: false
UseMousePassThoughWindow: true
Debug:
Expand Down
88 changes: 88 additions & 0 deletions include/Engine/Monitors.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#pragma once

#include "Engine/Vector2.hpp"

#include <GLFW/glfw3.h>

#include <vector>

class Monitors
{
protected:
std::vector<GLFWmonitor*> monitors;

public:
void init()
{
int monitorCount;
GLFWmonitor** pMonitors = glfwGetMonitors(&monitorCount);
monitors.reserve(monitorCount);

for (int i = 0; i < monitorCount; ++i)
{
addMonitor(pMonitors[i]);
glfwSetMonitorUserPointer(pMonitors[i], this);
}
}

void getMainMonitorWorkingArea(Vec2i& position, Vec2i& size) const
{
glfwGetMonitorWorkarea(glfwGetPrimaryMonitor(), &position.x, &position.y, &size.x, &size.y);
}

Vec2i getMonitorsSize() const
{
Vec2i size = Vec2i::zero();
const GLFWvidmode* currentVideoMode;
for (int i = 0; i < monitors.size(); i++)
{
currentVideoMode = glfwGetVideoMode(monitors[i]);
size.x += currentVideoMode->width;
size.y += currentVideoMode->height;

int xpos, ypos, width, height;
glfwGetMonitorWorkarea(monitors[i], &xpos, &ypos, &width, &height);
}
return size;
}

void getMonitorWorkingArea(int index, Vec2i& position, Vec2i& size) const
{
glfwGetMonitorWorkarea(monitors[index], &position.x, &position.y, &size.x, &size.y);
}

Vec2i getMonitorPhysicalSize() const
{
Vec2i sizeMM = Vec2i::zero();
int width_mm, height_mm;
for (int i = 0; i < monitors.size(); i++)
{
glfwGetMonitorPhysicalSize(monitors[i], &width_mm, &height_mm);
sizeMM.x += width_mm;
sizeMM.y += height_mm;
}
return sizeMM;
}

void addMonitor(GLFWmonitor* monitor)
{
monitors.emplace_back(monitor);
}

void removeMonitor(const GLFWmonitor* monitor)
{
for (int i = 0; i < monitors.size(); ++i)
{
if (monitors[i] == monitor)
{
monitors.erase(monitors.begin() + i);
break;
}
}
}

int getMonitorsCount() const
{
return monitors.size();
}
};
97 changes: 65 additions & 32 deletions include/Engine/PhysicSystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,34 +25,66 @@ class PhysicSystem
return std::abs(data.gravityDir.dot(data.velocity)) < data.isGroundedDetection;
}

static bool isRectAOutsideRectB(const Vec2i posA, const Vec2i sizeA, const Vec2i posB, const Vec2i sizeB)
{
// Check if the rectangles are disjoint (i.e. do not overlap)
return posA.x + sizeA.x < posB.x || posA.x > posB.x + sizeB.x || posA.y + sizeA.y < posB.y ||
posA.y > posB.y + sizeB.y;
}


void computeMonitorCollisions()
{
if (data.petPos.x < 0.f)
{
data.petPos.x = 0.f;
data.velocity = data.velocity.reflect(Vec2::right()) * data.bounciness;
}
std::vector<Vec2i> monitorsPosition;
std::vector<Vec2i> monitorSize;
bool isOutside = true;

if (data.petPos.y < 0.f)
// 1: Check if pet is outside of all monitors
for (int i = 0; i < data.monitors.getMonitorsCount(); ++i)
{
data.petPos.y = 0.f;
data.velocity = data.velocity.reflect(Vec2::down()) * data.bounciness;
monitorsPosition.emplace_back();
monitorSize.emplace_back();
data.monitors.getMonitorWorkingArea(i, monitorsPosition[i], monitorSize[i]);
isOutside &= isRectAOutsideRectB(data.petPos, data.petSize, monitorsPosition[i], monitorSize[i]);
}

if (data.petPos.x > data.petPosLimit.x)
// 2: If pet is outside need correction
float minSqrDistance = FLT_MAX;
Vec2 reelPositionCorrection;
if (isOutside)
{
data.petPos.x = static_cast<float>(data.petPosLimit.x);
data.velocity = data.velocity.reflect(Vec2::left()) * data.bounciness;
}
for (int i = 0; i < data.monitors.getMonitorsCount(); ++i)
{
Vec2 positionCorrection = data.petPos;

if (data.petPos.y > data.petPosLimit.y)
{
data.petPos.y = static_cast<float>(data.petPosLimit.y);
data.velocity = data.velocity.reflect(Vec2::up()) * data.bounciness;
if (data.petPos.x < monitorsPosition[i].x)
{
positionCorrection.x = monitorsPosition[i].x;
}
else if (data.petPos.x + data.petSize.x > monitorsPosition[i].x + monitorSize[i].x)
{
positionCorrection.x = monitorsPosition[i].x + monitorSize[i].x - data.petSize.x;
}

if (data.petPos.y < monitorsPosition[i].y)
{
positionCorrection.y = monitorsPosition[i].y;
}
else if (data.petPos.y + data.petSize.y > monitorsPosition[i].y + monitorSize[i].y)
{
positionCorrection.y = monitorsPosition[i].y + monitorSize[i].y - data.petSize.y;
}

float currentSqrDistance = (positionCorrection - data.petPos).sqrLength();
if (currentSqrDistance < minSqrDistance)
{
minSqrDistance = currentSqrDistance;
reelPositionCorrection = positionCorrection;
}
}

// check if is grounded
data.isGrounded = checkIsGrounded();
data.velocity *= !data.isGrounded; // reset velocity if is grounded
data.velocity = data.velocity.reflect((reelPositionCorrection - data.petPos).normalized()) * data.bounciness;
data.petPos = reelPositionCorrection;
}
}

Expand All @@ -71,10 +103,10 @@ class PhysicSystem
const float xPadding = prevToNewWinPos.x < 0.f ? prevToNewWinPos.x : 0.f;
const float yPadding = prevToNewWinPos.y < 0.f ? prevToNewWinPos.y : 0.f;

screenShootPosX = static_cast<int>(data.petPos.x + data.petSize.x / 2.f + xPadding - data.footBasasementWidth / 2.f);
screenShootPosY = static_cast<int>(data.petPos.y + data.petSize.y + 1 + yPadding - data.footBasasementHeight / 2.f);
screenShootSizeX = static_cast<int>(abs(prevToNewWinPos.x) + data.footBasasementWidth);
screenShootSizeY = static_cast<int>(abs(prevToNewWinPos.y) + data.footBasasementHeight);
screenShootPosX = static_cast<int>(data.petPos.x + data.petSize.x / 2.f + xPadding - data.footBasementWidth / 2.f);
screenShootPosY = static_cast<int>(data.petPos.y + data.petSize.y + 1 + yPadding - data.footBasementHeight / 2.f);
screenShootSizeX = static_cast<int>(abs(prevToNewWinPos.x) + data.footBasementWidth);
screenShootSizeY = static_cast<int>(abs(prevToNewWinPos.y) + data.footBasementHeight);
}

ScreenShoot screenshoot(screenShootPosX, screenShootPosY, screenShootSizeX, screenShootSizeY);
Expand Down Expand Up @@ -155,25 +187,25 @@ class PhysicSystem
int width = data.pEdgeDetectionTexture->getWidth();
int height = data.pEdgeDetectionTexture->getHeight();

float row = prevToNewWinPosDir.y < 0.f ? height - data.footBasasementHeight : 0.f;
float column = prevToNewWinPosDir.x < 0.f ? width - data.footBasasementWidth : 0.f;
float row = prevToNewWinPosDir.y < 0.f ? height - data.footBasementHeight : 0.f;
float column = prevToNewWinPosDir.x < 0.f ? width - data.footBasementWidth : 0.f;

int iterationCount = iterationOnX ? width - data.footBasasementWidth : height - data.footBasasementHeight;
int iterationCount = iterationOnX ? width - data.footBasementWidth : height - data.footBasementHeight;
for (int i = 0; i < iterationCount + 1; i++)
{
float count = 0;

for (int y = 0; y < data.footBasasementHeight; y++)
for (int y = 0; y < data.footBasementHeight; y++)
{
for (int x = 0; x < data.footBasasementWidth; x++)
for (int x = 0; x < data.footBasementWidth; x++)
{
// flip Y and find index
int rowFlipped = height - 1 - (int)row - y;
int index = (rowFlipped * width + (int)column + x) * dataPerPixel;
count += pixels[index] == 255;
}
}
count /= data.footBasasementWidth * data.footBasasementHeight;
count /= data.footBasementWidth * data.footBasementHeight;

if (count > data.collisionPixelRatioStopMovement)
{
Expand Down Expand Up @@ -205,10 +237,11 @@ class PhysicSystem

const Vec2 prevWinPos = data.petPos;
// Pos = PrevPos + V * Time
const Vec2 newWinPos = data.petPos + ((data.continusVelocity + data.velocity) * (1.f - data.friction) *
const Vec2 newWinPos = data.petPos + ((data.continuousVelocity + data.velocity) * (1.f - data.friction) *
data.pixelPerMeter * (float)deltaTime);

const Vec2 prevToNewWinPos = newWinPos - prevWinPos;
if ((prevToNewWinPos.sqrLength() <= data.continusCollisionMaxSqrVelocity && prevToNewWinPos.y > 0.f) ||
if ((prevToNewWinPos.sqrLength() <= data.continuousCollisionMaxSqrVelocity && prevToNewWinPos.y > 0.f) ||
data.debugEdgeDetection)
{
Vec2 newPos;
Expand All @@ -233,7 +266,7 @@ class PhysicSystem
if (data.isGrounded && data.petPos.y != data.petPosLimit.y)
{
Vec2 newPos;
Vec2 footBasement((float)data.footBasasementWidth, (float)data.footBasasementHeight);
Vec2 footBasement((float)data.footBasementWidth, (float)data.footBasementHeight);
data.isGrounded = CatpureScreenCollision(footBasement, newPos);
}

Expand Down
14 changes: 7 additions & 7 deletions include/Engine/Settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ class Setting
data.gravity = Vec2{nodesSection["GravityX"].as<float>(), nodesSection["GravityY"].as<float>()};
data.gravityDir = data.gravity.normalized();
data.friction = std::clamp(nodesSection["Friction"].as<float>(), 0.f, 1.f);
data.continusCollisionMaxSqrVelocity =
std::max(nodesSection["ContinusCollisionMaxVelocity"].as<float>(), 0.f);
data.continusCollisionMaxSqrVelocity *= data.continusCollisionMaxSqrVelocity;
data.footBasasementWidth = std::max(nodesSection["FootBasasementWidth"].as<int>(), 2);
data.footBasasementHeight = std::max(nodesSection["FootBasasementHeight"].as<int>(), 2);
data.continuousCollisionMaxSqrVelocity =
std::max(nodesSection["ContinuousCollisionMaxVelocity"].as<float>(), 0.f);
data.continuousCollisionMaxSqrVelocity *= data.continuousCollisionMaxSqrVelocity;
data.footBasementWidth = std::max(nodesSection["FootBasementWidth"].as<int>(), 2);
data.footBasementHeight = std::max(nodesSection["FootBasementHeight"].as<int>(), 2);
data.collisionPixelRatioStopMovement =
std::clamp(nodesSection["CollisionPixelRatioStopMovement"].as<float>(), 0.f, 1.f);
data.isGroundedDetection = std::max(nodesSection["IsGroundedDetection"].as<float>(), 0.f);
Expand All @@ -69,7 +69,7 @@ class Setting

data.showWindow = nodesSection["ShowWindow"].as<bool>();
data.showFrameBufferBackground = nodesSection["ShowFrameBufferBackground"].as<bool>();
data.useFowardWindow = nodesSection["UseFowardWindow"].as<bool>();
data.useForwardWindow = nodesSection["UseForwardWindow"].as<bool>();
data.useMousePassThoughWindow = nodesSection["UseMousePassThoughWindow"].as<bool>();
}

Expand All @@ -81,7 +81,7 @@ class Setting

data.showWindow = nodesSection["ShowWindow"].as<bool>();
data.showFrameBufferBackground = nodesSection["ShowFrameBufferBackground"].as<bool>();
data.useFowardWindow = nodesSection["UseFowardWindow"].as<bool>();
data.useForwardWindow = nodesSection["UseForwardWindow"].as<bool>();
data.useMousePassThoughWindow = nodesSection["UseMousePassThoughWindow"].as<bool>();
}

Expand Down
3 changes: 2 additions & 1 deletion include/Engine/SpriteSheet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class SpriteSheet : public Texture
data.petSize.y = height * data.scale;
data.windowSize.x = data.petSize.x + data.windowExt.x + data.windowMinExt.x;
data.windowSize.y = data.petSize.y + data.windowExt.y + data.windowMinExt.y;
data.petPosLimit = {data.videoMode->width - data.petSize.x, data.videoMode->height - data.petSize.y};
Vec2i monitorSize = data.monitors.getMonitorsSize();
data.petPosLimit = {monitorSize.x - data.petSize.x, monitorSize.y - data.petSize.y};
glfwSetWindowSize(data.window, data.windowSize.x, data.windowSize.y);

float hScale = 1.f / tileCount;
Expand Down
1 change: 1 addition & 0 deletions include/Engine/Texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>

#include "Engine/Log.hpp"
#include "Engine/Vector2.hpp"

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
Expand Down
6 changes: 2 additions & 4 deletions include/Engine/Vector2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ union Vector2 {
{
}

constexpr Vector2(const T x_, const T y_ = static_cast<T>(0)) noexcept : x{x_}, y{y_}
constexpr Vector2(const T x_, const T y_) noexcept : x{x_}, y{y_}
{
}

Expand Down Expand Up @@ -352,9 +352,7 @@ union Vector2 {

constexpr Vector2 operator/(const T k) const noexcept
{
const float reciprocal{static_cast<T>(1) / k};

return {x * reciprocal, y * reciprocal};
return {x / k, y / k};
}

template <typename U>
Expand Down
16 changes: 16 additions & 0 deletions include/Engine/Window.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ void mousButtonCallBack(GLFWwindow* window, int button, int action, int mods)
}
}

void setMonitorCallback(GLFWmonitor* monitor, int event)
{
GameData& datas = *static_cast<GameData*>(glfwGetMonitorUserPointer(monitor));

switch (event)
{
case GLFW_CONNECTED:
datas.monitors.addMonitor(monitor);
break;

case GLFW_DISCONNECTED:
datas.monitors.removeMonitor(monitor);
break;
}
}

void processInput(GLFWwindow* window)
{
GameData& datas = *static_cast<GameData*>(glfwGetWindowUserPointer(window));
Expand Down
4 changes: 2 additions & 2 deletions include/Game/Animations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ class PetWalkNode : public AnimationNode
{
AnimationNode::onEnter(blackBoard);
blackBoard.side = randNum(0, 1);
blackBoard.continusVelocity += baseDir * (blackBoard.side * 2.f - 1.f) * thrust;
blackBoard.continuousVelocity += baseDir * (blackBoard.side * 2.f - 1.f) * thrust;
}

void onExit(GameData& blackBoard) override
{
AnimationNode::onExit(blackBoard);
blackBoard.continusVelocity -= baseDir * (blackBoard.side * 2.f - 1.f) * thrust;
blackBoard.continuousVelocity -= baseDir * (blackBoard.side * 2.f - 1.f) * thrust;
}
};
Loading