diff --git a/.gitignore b/.gitignore index d7716a4..e024c33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ build/* -EyeRendererOld/build/Desktop_Qt_6_7_0-Debug +out/* CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c069d6..00b2780 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,10 +16,13 @@ set(CMAKE_CXX_EXTENSIONS ON) set(OpenCV_STATIC ON) find_package( OpenCV REQUIRED ) - find_package( Eigen3 REQUIRED ) find_package( Iconv REQUIRED ) +if (WIN32) + find_package(glm CONFIG REQUIRED) +endif() + add_subdirectory(libs) include_directories( ${OpenCV_INCLUDE_DIRS} ) @@ -53,14 +56,18 @@ set(PROJ_LINK_LIBS) set(PROJ_SRC) # Add all files/folders under src folder automatically to the project -file(GLOB_RECURSE PROJ_SRC src/*.h src/*.cpp) +file(GLOB PROJ_SRC src/*.h src/*.cpp) +file(GLOB_RECURSE srcLinux src/linux/*.h src/linux/*.cpp) +file(GLOB_RECURSE srcWindows src/windows/*.h src/windows/*.cpp) ### ### Compiler settings ### -add_definitions( - -fPIC -fcommon - ) +if(UNIX) + add_definitions( + -fPIC -fcommon + ) +endif() ### ### GLFW @@ -78,16 +85,22 @@ if(KITGL_SUPPORT_GLFW) list(APPEND PROJ_LINK_LIBS glfw) endif(KITGL_SUPPORT_GLFW) -list(APPEND PROJ_LINK_LIBS Xinerama) +if(UNIX) + list(APPEND PROJ_LINK_LIBS Xinerama) +endif() + +add_executable(${PROJECT_NAME}) + +target_sources(${PROJECT_NAME} PRIVATE ${PROJ_SRC}) +if (WIN32) + message(STATUS "Adding Windows sources") + target_sources(${PROJECT_NAME} PRIVATE ${srcWindows}) +elseif(UNIX) + message(STATUS "Adding Linux sources") + target_sources(${PROJECT_NAME} PRIVATE ${srcLinux}) +endif() -### -### Generating the project files -### -add_executable(${PROJECT_NAME} ${PROJ_SRC}) -### -### Linking to the project -### target_link_libraries(${PROJECT_NAME} PRIVATE RenderLib ImageProcessingToolsLib @@ -95,6 +108,15 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Iconv::Iconv ${PROJ_LINK_LIBS}) +if (WIN32) + target_link_libraries(${PROJECT_NAME} PRIVATE glm::glm-header-only GdiPlus) + + get_target_property(GLM_INCLUDE_DIR glm::glm-header-only INTERFACE_INCLUDE_DIRECTORIES) + message(STATUS "GLM include dir: ${GLM_INCLUDE_DIR}") + target_include_directories(${PROJECT_NAME} PRIVATE ${GLM_INCLUDE_DIR}) +endif() + + file(COPY "${CMAKE_SOURCE_DIR}/data" DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) add_custom_target(Other SOURCES diff --git a/libs/BasicToolsLib b/libs/BasicToolsLib index 676501e..aeecdd1 160000 --- a/libs/BasicToolsLib +++ b/libs/BasicToolsLib @@ -1 +1 @@ -Subproject commit 676501e1d42d842412e83f90cfa9ced2d1902683 +Subproject commit aeecdd1c26ed9511d6a6cd2bcb576877180d4762 diff --git a/libs/ImageProcessingToolsLib b/libs/ImageProcessingToolsLib index 8281080..4bb6ad5 160000 --- a/libs/ImageProcessingToolsLib +++ b/libs/ImageProcessingToolsLib @@ -1 +1 @@ -Subproject commit 828108002cb02b4d52a76e89932689ec18407995 +Subproject commit 4bb6ad55d13806d5797f9e3d2b2736dd40f5adab diff --git a/libs/RenderLib b/libs/RenderLib index a3cda51..4aecb73 160000 --- a/libs/RenderLib +++ b/libs/RenderLib @@ -1 +1 @@ -Subproject commit a3cda516b61f8b2f6978ad3057c93bd7b69f6776 +Subproject commit 4aecb73e4b2a84c5c64da584639ab9a245c94d24 diff --git a/src/AbstractScreenCapturer.h b/src/AbstractScreenCapturer.h new file mode 100644 index 0000000..cff9a75 --- /dev/null +++ b/src/AbstractScreenCapturer.h @@ -0,0 +1,16 @@ +#ifndef AbstractScreenCapturer_H +#define AbstractScreenCapturer_H + +#include + +#include "ImageData.h" +#include "MonitorPosition.h" + +class AbstractScreenCapturer +{ +public: + virtual ~AbstractScreenCapturer() = default; + virtual std::unordered_map Capture() = 0; +}; + +#endif diff --git a/src/Eye3dModel.cpp b/src/Eye3dModel.cpp index 5fc27b9..4690fc0 100644 --- a/src/Eye3dModel.cpp +++ b/src/Eye3dModel.cpp @@ -6,6 +6,11 @@ #include "objects/GlRenderSphereArc.h" #include "objects/GlRenderSpherePolar.h" +#ifndef M_PI +#define M_PI 3.141592 +#endif + + namespace { const float upperLidOpenAngle = 0.75f; diff --git a/src/EyeFaceAnalyzer.cpp b/src/EyeFaceAnalyzer.cpp index 7fd7cc2..585194f 100644 --- a/src/EyeFaceAnalyzer.cpp +++ b/src/EyeFaceAnalyzer.cpp @@ -43,8 +43,9 @@ void EyeFaceAnalyzer::RunThreadedDetect() { while (keepRunning) { + std::optional newFacePosition = Detect(); faceMutex.lock(); - facePosition = Detect(); + facePosition = newFacePosition; faceMutex.unlock(); } } diff --git a/src/LinuxScreenCapturer.h b/src/LinuxScreenCapturer.h deleted file mode 100644 index 5b6857c..0000000 --- a/src/LinuxScreenCapturer.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef LINUXSCREENCAPTURER_H -#define LINUXSCREENCAPTURER_H - -#include "ImageData.h" - -#include - -struct MonitorPosition -{ - MonitorPosition(); - - bool operator==(const MonitorPosition other) const; - - int xOrigin; - int yOrigin; - -}; - -namespace std { -template <> -struct hash { - size_t operator()(const MonitorPosition& key) const { - size_t h1 = std::hash()(key.xOrigin); - size_t h2 = std::hash()(key.yOrigin); - return h1 ^ (h2 << 1); - } -}; -} - -class LinuxScreenCapturer -{ -public: - LinuxScreenCapturer() = default; - - virtual std::unordered_map Capture(); -}; - -#endif // LINUXSCREENCAPTURER_H diff --git a/src/MonitorPosition.cpp b/src/MonitorPosition.cpp new file mode 100644 index 0000000..fe65bf4 --- /dev/null +++ b/src/MonitorPosition.cpp @@ -0,0 +1,12 @@ +#include "MonitorPosition.h" + +MonitorPosition::MonitorPosition() + : xOrigin(0), yOrigin(0) +{ +} + +bool MonitorPosition::operator==(const MonitorPosition other) const +{ + return xOrigin == other.xOrigin && yOrigin == other.yOrigin; +} + diff --git a/src/MonitorPosition.h b/src/MonitorPosition.h new file mode 100644 index 0000000..661c1bb --- /dev/null +++ b/src/MonitorPosition.h @@ -0,0 +1,28 @@ +#ifndef MonitorPosition_H +#define MonitorPosition_H + +#include + +struct MonitorPosition +{ + MonitorPosition(); + + bool operator==(const MonitorPosition other) const; + + int xOrigin; + int yOrigin; + +}; + +namespace std { + template <> + struct hash { + size_t operator()(const MonitorPosition& key) const { + size_t h1 = std::hash()(key.xOrigin); + size_t h2 = std::hash()(key.yOrigin); + return h1 ^ (h2 << 1); + } + }; +} + +#endif diff --git a/src/LinuxScreenCapturer.cpp b/src/linux/LinuxScreenCapturer.cpp similarity index 92% rename from src/LinuxScreenCapturer.cpp rename to src/linux/LinuxScreenCapturer.cpp index 062b6cb..17a610c 100644 --- a/src/LinuxScreenCapturer.cpp +++ b/src/linux/LinuxScreenCapturer.cpp @@ -65,17 +65,6 @@ namespace } } -MonitorPosition::MonitorPosition() -: xOrigin(0), yOrigin(0) -{ -} - -bool MonitorPosition::operator==(const MonitorPosition other) const -{ - return xOrigin == other.xOrigin && yOrigin == other.yOrigin; -} - - std::unordered_map LinuxScreenCapturer::Capture() { std::unordered_map screenshots; diff --git a/src/linux/LinuxScreenCapturer.h b/src/linux/LinuxScreenCapturer.h new file mode 100644 index 0000000..d5e483b --- /dev/null +++ b/src/linux/LinuxScreenCapturer.h @@ -0,0 +1,19 @@ +#ifndef LINUXSCREENCAPTURER_H +#define LINUXSCREENCAPTURER_H + +#include + +#include "../AbstractScreenCapturer.h" +#include "ImageData.h" +#include "../MonitorPosition.h" + +class LinuxScreenCapturer : public AbstractScreenCapturer +{ +public: + LinuxScreenCapturer() = default; + virtual ~LinuxScreenCapturer() = default; + + std::unordered_map Capture() override; +}; + +#endif // LINUXSCREENCAPTURER_H diff --git a/src/main.cpp b/src/main.cpp index db1ce81..97ca8f6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,13 @@ #include "Eye.h" #include "EyeFaceAnalyzer.h" -#include "LinuxScreenCapturer.h" +#include "MonitorPosition.h" + +#ifdef __linux + #include "linux/LinuxScreenCapturer.h" +#elif defined WIN32 + #include "windows/WindowsScreenCapturer.h" +#endif // TODO : Use a DEFINE for the data dir, and update Cmake accordingly. // For Linux, it should be /usr/share/the-eye. @@ -64,38 +70,54 @@ ImageData FindRightScreenshot(const std::unordered_mapsecond; } -int main() +void errorCallback(int error, const char* description) { - if (!glfwInit()) return -1; + fprintf(stderr, "GLFW Error (%d): %s\n", error, description); +} - LinuxScreenCapturer screenshotCapturer; - const std::unordered_map screenshots = screenshotCapturer.Capture(); +AbstractScreenCapturer* CreateScreenCapturer() +{ +#ifdef __linux + return new LinuxScreenCapturer(); +#elif defined WIN32 + return new WindowsScreenCapturer(); +#endif +} - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - const int monitorWidth = mode->width; - const int monitorHeight = mode->height; +std::optional> InitializeGlDisplay() +{ + GLFWmonitor* monitor = nullptr; + GLFWwindow* window = nullptr; - GLFWwindow* window = glfwCreateWindow(monitorWidth, monitorHeight, "Eye Renderer", monitor, nullptr); - if (!window) - { - glfwTerminate(); - return -1; - } + glfwSetErrorCallback(errorCallback); + if (!glfwInit()) + return std::nullopt; + + monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + const int monitorWidth = mode->width; + const int monitorHeight = mode->height; - glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); - glfwSetKeyCallback(window, keyPressCallback); - glfwSetMouseButtonCallback(window, mouseButtonCallback); - glfwSetCursorPosCallback(window, mouseMoveCallback); - glfwMakeContextCurrent(window); + window = glfwCreateWindow(monitorWidth, monitorHeight, "Eye Renderer", monitor, nullptr); + if (!window) + return std::nullopt; - gladLoadGL(glfwGetProcAddress); + glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_FALSE); + glfwSetKeyCallback(window, keyPressCallback); + glfwSetMouseButtonCallback(window, mouseButtonCallback); + glfwSetCursorPosCallback(window, mouseMoveCallback); + glfwMakeContextCurrent(window); - glViewport(0, 0, monitorWidth, monitorHeight); + gladLoadGL(glfwGetProcAddress); + glViewport(0, 0, monitorWidth, monitorHeight); - OrbitCamera camera(Vector3(0, 0, 0)); - auto renderer = new GlRenderer(&camera); - renderer->SetClearColor(0.0f, 0.0f, 0.0f); + return std::make_pair(monitor, window); +} + +int main() +{ + auto screenshotCapturer = CreateScreenCapturer(); + const std::unordered_map screenshots = screenshotCapturer->Capture(); std::mutex faceMutex; std::optional facePosition; @@ -105,52 +127,66 @@ int main() const bool ok = faceAnalyzer.Initialize(); if (ok) { - faceAnalyzer.RunThreadedDetection(); + faceAnalyzer.RunThreadedDetection(); + + auto glDisplay = InitializeGlDisplay(); + if (glDisplay.has_value()) + { + OrbitCamera camera(Vector3(0, 0, 0)); + auto renderer = new GlRenderer(&camera); + renderer->SetClearColor(0.0f, 0.0f, 0.0f); + + Eye eye; + const ImageData rightScreen = FindRightScreenshot(screenshots, glDisplay->first); + eye.Initialize(renderer, rightScreen); + + float deltaT = 0.f; - Eye eye; - const ImageData rightScreen = FindRightScreenshot(screenshots, monitor); - eye.Initialize(renderer, rightScreen); + while (!glfwWindowShouldClose(glDisplay->second)) + { + const auto startIteration = std::chrono::steady_clock::now(); + glfwPollEvents(); - float deltaT = 0.f; + std::optional* faceDataToUse = nullptr; + bool tookTheLock = false; + if (faceMutex.try_lock()) + { + faceDataToUse = &facePosition; + tookTheLock = true; + } + else + faceDataToUse = &lastFacePosition; - while (!glfwWindowShouldClose(window)) - { - const auto startIteration = std::chrono::steady_clock::now(); - glfwPollEvents(); + eye.Update(*faceDataToUse, deltaT); - std::optional* faceDataToUse = nullptr; - bool tookTheLock = false; - if (faceMutex.try_lock()) - { - faceDataToUse = &facePosition; - tookTheLock = true; - } - else - faceDataToUse = &lastFacePosition; + if (tookTheLock) + { + lastFacePosition = facePosition; + faceMutex.unlock(); + } - eye.Update(*faceDataToUse, deltaT); + renderer->Render(); - if (tookTheLock) - lastFacePosition = facePosition; - faceMutex.unlock(); + glfwSwapBuffers(glDisplay->second); - renderer->Render(); + const auto endIteration = std::chrono::steady_clock::now(); + deltaT = std::chrono::duration(endIteration - startIteration).count(); + globalT += deltaT; + } - glfwSwapBuffers(window); + delete renderer; + } + else + std::cout << "Error creating OpenGl display." << std::endl; - const auto endIteration = std::chrono::steady_clock::now(); - deltaT = std::chrono::duration(endIteration - startIteration).count(); - globalT += deltaT; - } + glfwTerminate(); - faceAnalyzer.StopThreadedDetection(); + faceAnalyzer.StopThreadedDetection(); } else - std::cout << "Error initializing Face analyzer. Check if you have a working camera and if the data folder is accessible." << std::endl; + std::cout << "Error initializing Face analyzer. Check if you have a working camera and if the data folder is accessible." << std::endl; - // Clean up - delete renderer; - glfwTerminate(); + delete screenshotCapturer; return ok ? 0 : 1; } diff --git a/src/windows/WindowsScreenCapturer.cpp b/src/windows/WindowsScreenCapturer.cpp new file mode 100644 index 0000000..015197d --- /dev/null +++ b/src/windows/WindowsScreenCapturer.cpp @@ -0,0 +1,67 @@ +#include "WindowsScreenCapturer.h" + +#include +#include + +using namespace Gdiplus; + + +WindowsScreenCapturer::WindowsScreenCapturer() +{ + GdiplusStartupInput gdiplusStartupInput; + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); +} + +WindowsScreenCapturer::~WindowsScreenCapturer() +{ + GdiplusShutdown(gdiplusToken); +} + +std::unordered_map WindowsScreenCapturer::Capture() +{ + std::unordered_map screenshots; + + HDC hScreenDC = GetDC(HWND_DESKTOP); + HDC hMemoryDC = CreateCompatibleDC(hScreenDC); + + const int width = GetSystemMetrics(SM_CXSCREEN); + const int height = GetSystemMetrics(SM_CYSCREEN); + + HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height); + HGDIOBJ hOldBitmap = SelectObject(hMemoryDC, hBitmap); + + BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY); + + hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap); + + BITMAPINFO bmpInfo; + ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpInfo.bmiHeader.biWidth = width; + bmpInfo.bmiHeader.biHeight = -height; // Top-down DIB + bmpInfo.bmiHeader.biPlanes = 1; + bmpInfo.bmiHeader.biBitCount = 32; + bmpInfo.bmiHeader.biCompression = BI_RGB; + + ImageData screenData; + screenData.width = width; + screenData.height = height; + screenData.channels = bmpInfo.bmiHeader.biBitCount / 8; + const size_t dataSize = width * height * screenData.channels; + screenData.data = new unsigned char[dataSize]; + + GetDIBits(hMemoryDC, hBitmap, 0, height, NULL, &bmpInfo, DIB_RGB_COLORS); + GetDIBits(hMemoryDC, hBitmap, 0, height, screenData.data, &bmpInfo, DIB_RGB_COLORS); + SelectObject(hMemoryDC, hOldBitmap); + + + DeleteObject(hBitmap); + DeleteDC(hMemoryDC); + ReleaseDC(HWND_DESKTOP, hScreenDC); + + MonitorPosition position; + position.xOrigin = 0; + position.yOrigin = 0; + screenshots[position] = screenData; + return screenshots; +} \ No newline at end of file diff --git a/src/windows/WindowsScreenCapturer.h b/src/windows/WindowsScreenCapturer.h new file mode 100644 index 0000000..8d3f5aa --- /dev/null +++ b/src/windows/WindowsScreenCapturer.h @@ -0,0 +1,21 @@ +#ifndef WindowsScreenCapturer_H +#define WindowsScreenCapturer_H + +#include "../AbstractScreenCapturer.h" + +#include +#include +#include "../MonitorPosition.h" + +class WindowsScreenCapturer : public AbstractScreenCapturer +{ +public: + WindowsScreenCapturer(); + ~WindowsScreenCapturer(); + + std::unordered_map Capture() override; + +private: + ULONG_PTR gdiplusToken; +}; +#endif diff --git a/vcpkg.json b/vcpkg.json index d11a037..7c0c197 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -8,6 +8,12 @@ "glm", "libiconv" ], + "overrides": [ + { + "name": "eigen3", + "version": "3.4.0" + } + ], "builtin-baseline" : "4334d8b4c8916018600212ab4dd4bbdc343065d1" }