Skip to content
Open
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
44 changes: 43 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
matrix-no-macos: ${{ steps.set-matrix.outputs.matrix-no-macos }}
steps:
- id: set-matrix
shell: bash
Expand All @@ -25,7 +26,42 @@ jobs:
else
RESULT=$(echo "$BASE" | jq -c '.')
fi
RESULT_NO_MACOS=$(echo "$RESULT" | jq -c '[ .[] | select (.platform != "macos") ]')

echo "matrix={\"include\":$RESULT}" >> "$GITHUB_OUTPUT"
echo "matrix-no-macos={\"include\":$RESULT_NO_MACOS}" >> "$GITHUB_OUTPUT"

build-bindings-provider:
name: Build bindings provider for ${{ matrix.os }}
needs: [setup-matrix]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix-no-macos) }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: recursive
- if: matrix.platform == 'linux'
name: Install GCC
uses: egor-tensin/setup-gcc@v2
with:
version: 16
- name: Get CMake
uses: lukka/get-cmake@latest
- name: Configure
run: cmake -S bindings-provider/ -B bindings-provider/build -DCMAKE_BUILD_TYPE=Release
- name: Build
run: cmake --build bindings-provider/build --config Release -j6
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: bindings-provider-${{ matrix.platform }}-${{ matrix.os }}
path: |
bindings-provider/build/slimevr-bindings-provider
bindings-provider/build/Release/SlimeVR-Bindings-Provider.exe

gui-checks:
name: Gui Checks
runs-on: ubuntu-latest
Expand Down Expand Up @@ -125,7 +161,7 @@ jobs:

package-desktop:
name: Package Desktop (${{ matrix.platform }} - ${{ matrix.os }})
needs: [setup-matrix, build-server-jar, build-gui-frontend]
needs: [setup-matrix, build-server-jar, build-gui-frontend, build-bindings-provider]
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup-matrix.outputs.matrix) }}
Expand All @@ -149,6 +185,12 @@ jobs:
with:
name: server-jar
path: server
- name: Download Bindings Provider Artifacts
uses: actions/download-artifact@v8
with:
pattern: bindings-provider-*
path: bindings-provider/build
merge-multiple: true
- name: Download GUI Dist
uses: actions/download-artifact@v8
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "solarxr-protocol"]
path = solarxr-protocol
url = https://github.com/SlimeVR/SolarXR-Protocol.git
[submodule "svr-bindings-provider/openvr"]
path = bindings-provider/openvr
url = https://github.com/ValveSoftware/openvr.git
12 changes: 12 additions & 0 deletions bindings-provider/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Garbage left behind on Windows

.vs/
out/
CMakeFiles/
vcpkg_installed/
src/resources/resources.hpp
CMakeCache.txt
build.ninja
*.cmake
*.dll
*.log
78 changes: 78 additions & 0 deletions bindings-provider/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
cmake_minimum_required(VERSION 3.26)

project(SlimeVR-Bindings-Provider)

set(SOLARXR_PROTOCOL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../solarxr-protocol")
set(FLATBUFFERS_GENERATED_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../solarxr-protocol/protocol/cpp")

# These are used to determine the OpenVR library path
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(PROCESSOR_ARCH "64")
else()
set(PROCESSOR_ARCH "32")
endif()
if(WIN32)
set(OPENVR_LIBRARY_NAME "openvr_api")
set(OPENVR_LIBRARY_EXT "dll")
set(PLATFORM_NAME "win")
elseif(APPLE)
set(OPENVR_LIBRARY_NAME "libopenvr_api")
set(OPENVR_LIBRARY_EXT "dylib")
set(PLATFORM_NAME "osx")
elseif(LINUX)
set(OPENVR_LIBRARY_NAME "libopenvr_api")
set(OPENVR_LIBRARY_EXT "so")
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(PLATFORM_NAME "linuxarm")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(PLATFORM_NAME "linux")
else()
message(FATAL_ERROR "Unknown/unsupported CPU architecture")
endif()
else()
message(FATAL_ERROR "Unknown/unsupported platform")
endif()

set(OPENVR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/openvr")

message(STATUS "OpenVR library search path: ${OPENVR_ROOT}/lib/${PLATFORM_NAME}${PROCESSOR_ARCH}")
find_library(OPENVR_LIBRARY NAMES openvr_api REQUIRED PATHS "${OPENVR_ROOT}/lib/${PLATFORM_NAME}${PROCESSOR_ARCH}/" NO_DEFAULT_PATH)
message(STATUS "Found OpenVR library at: ${OPENVR_LIBRARY}")

add_executable("${PROJECT_NAME}"
"${CMAKE_CURRENT_SOURCE_DIR}/src/paths.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/logger.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/solarxr.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/vr_utils.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp"
)
set_target_properties("${PROJECT_NAME}" PROPERTIES CXX_STANDARD 23)
target_include_directories("${PROJECT_NAME}" PRIVATE "${SOLARXR_PROTOCOL_ROOT}/lib/flatbuffers/include" "${SOLARXR_PROTOCOL_ROOT}/lib/flatbuffers/" "${FLATBUFFERS_GENERATED_ROOT}/include" "${CMAKE_CURRENT_SOURCE_DIR}/include" "${OPENVR_ROOT}/headers")
target_link_libraries("${PROJECT_NAME}" PRIVATE "${OPENVR_LIBRARY}")

if(LINUX)
set_target_properties("${PROJECT_NAME}" PROPERTIES OUTPUT_NAME slimevr-bindings-provider)
endif()

set(OPENVR_RUNTIME_LIBRARY "${OPENVR_ROOT}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH}/${OPENVR_LIBRARY_NAME}.${OPENVR_LIBRARY_EXT}")
message(STATUS "Found OpenVR runtime library: ${OPENVR_RUNTIME_LIBRARY}")
configure_file("${OPENVR_RUNTIME_LIBRARY}" "." COPYONLY)

# Embed the resources into resources.hpp
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
src/resources/manifest.vrmanifest
src/resources/action_manifest.json
src/resources/generic.json
src/resources/knuckles.json
src/resources/oculus_touch.json
src/resources/vive_controller.json
)
file(STRINGS src/resources/manifest.vrmanifest SVR_VRAPP_MANIFEST NEWLINE_CONSUME)
file(STRINGS src/resources/action_manifest.json SVR_VRAPP_ACTION_MANIFEST NEWLINE_CONSUME)
file(STRINGS src/resources/generic.json SVR_VRAPP_GENERIC_BINDS NEWLINE_CONSUME)
file(STRINGS src/resources/knuckles.json SVR_VRAPP_KNUCKLES_BINDS NEWLINE_CONSUME)
file(STRINGS src/resources/oculus_touch.json SVR_VRAPP_OCULUS_BINDS NEWLINE_CONSUME)
file(STRINGS src/resources/vive_controller.json SVR_VRAPP_VIVE_BINDS NEWLINE_CONSUME)

configure_file(src/resources/resources.hpp.in src/resources/resources.hpp @ONLY)
target_include_directories("${PROJECT_NAME}" PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/src")
1 change: 1 addition & 0 deletions bindings-provider/openvr
Submodule openvr added at 918253
22 changes: 22 additions & 0 deletions bindings-provider/src/logger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "logger.hpp"
#include "paths.hpp"

#ifdef _WIN32
#define WIN32_MEAN_AND_LEAN
#include <Windows.h>
#endif

Logger::Logger()
: log_stream(Paths::getLogPath() / "slimevr-bindings-provider.log",
std::ios::out | std::ios::app)
#ifdef _WIN32
,
should_log_to_std_streams(GetConsoleWindow() != nullptr)
#endif
{
}

Logger &Logger::get() {
static Logger logger;
return logger;
}
77 changes: 77 additions & 0 deletions bindings-provider/src/logger.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#pragma once

#include <cassert>
#include <chrono>
#include <format>
#include <fstream>
#include <iomanip>
#include <iostream>

class Logger {
private:
std::ofstream log_stream;
#ifdef _WIN32
bool should_log_to_std_streams;
#endif

template <bool important, typename... Args>
void log(std::string_view suffix, std::format_string<Args...> fmt,
Args &&...args) {
auto now = std::chrono::system_clock::now();
auto time_t = std::chrono::system_clock::to_time_t(now);

auto s = std::format(fmt, std::forward<Args>(args)...);
#ifdef _WIN32
if (should_log_to_std_streams) {
#endif
if constexpr (important)
std::cerr << suffix << ' ' << s << '\n';
else
std::cout << suffix << ' ' << s << '\n';
#ifdef _WIN32
}
#endif

log_stream << std::put_time(std::localtime(&time_t), "[%F %T]") //
<< ' ' << suffix << ' ' << s << '\n';
}

public:
Logger();

template <typename... Args>
void debug(std::format_string<Args...> fmt, Args &&...args) {
#ifndef NDEBUG
log<false>("[DEBUG]", fmt, std::forward<Args>(args)...);
#endif
}

template <typename... Args>
void info(std::format_string<Args...> fmt, Args &&...args) {
log<false>("[INFO]", fmt, std::forward<Args>(args)...);
}

template <typename... Args>
void warning(std::format_string<Args...> fmt, Args &&...args) {
log<true>("[WARN]", fmt, std::forward<Args>(args)...);
}

template <typename... Args>
void error(std::format_string<Args...> fmt, Args &&...args) {
log<true>("[ERROR]", fmt, std::forward<Args>(args)...);
}

void flush() {
#ifdef _WIN32
if (should_log_to_std_streams) {
#endif
std::cerr.flush();
std::cout.flush();
#ifdef _WIN32
}
#endif
log_stream.flush();
}

static Logger &get();
};
Loading