mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-07 00:00:21 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f60358eac | ||
|
|
85c6b3cea4 | ||
|
|
dda68d48b4 | ||
|
|
5c36f6e909 | ||
|
|
f112ca6768 | ||
|
|
a93dac0e28 | ||
|
|
35690d8521 | ||
|
|
1bed4afb97 | ||
|
|
6126280c40 | ||
|
|
f8abea143e | ||
|
|
ac16d42d01 |
No files matched your search
@@ -5,5 +5,6 @@ ipch
|
||||
*.aps
|
||||
*.user
|
||||
/OpenVR-SpaceCalibrator/x64/
|
||||
/OpenVR-SpaceCalibratorDriver/x64/
|
||||
/x64/
|
||||
/lib/boost*
|
||||
@@ -5,22 +5,22 @@ VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenVR-SpaceCalibrator", "OpenVR-SpaceCalibrator\OpenVR-SpaceCalibrator.vcxproj", "{63BAE169-D595-4464-8E7E-50D6FD379348}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenVR-SpaceCalibratorDriver", "OpenVR-SpaceCalibratorDriver\OpenVR-SpaceCalibratorDriver.vcxproj", "{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Debug|x64.Build.0 = Debug|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Debug|x86.Build.0 = Debug|Win32
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x64.ActiveCfg = Release|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x64.Build.0 = Release|x64
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x86.ActiveCfg = Release|Win32
|
||||
{63BAE169-D595-4464-8E7E-50D6FD379348}.Release|x86.Build.0 = Release|Win32
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Debug|x64.Build.0 = Debug|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Release|x64.ActiveCfg = Release|x64
|
||||
{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,75 +1,21 @@
|
||||
#include "stdafx.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.h"
|
||||
#include "IPCClient.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
|
||||
#include <lib_vrinputemulator/vrinputemulator.h>
|
||||
#include <openvr.h>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
enum CalibrationState
|
||||
|
||||
static IPCClient Driver;
|
||||
CalibrationContext CalCtx;
|
||||
|
||||
void InitCalibrator()
|
||||
{
|
||||
None,
|
||||
Begin,
|
||||
Rotation,
|
||||
Translation,
|
||||
};
|
||||
|
||||
struct CalibrationContext
|
||||
{
|
||||
CalibrationState state = None;
|
||||
int referenceID, targetID;
|
||||
|
||||
Eigen::Vector3d calibratedRotation;
|
||||
Eigen::Vector3d calibratedTranslation;
|
||||
|
||||
std::string calibratedTrackingSystem;
|
||||
|
||||
bool profileLoaded = false, validProfile = false;
|
||||
int ticksSinceScan = 0;
|
||||
};
|
||||
|
||||
|
||||
static vrinputemulator::VRInputEmulator InputEmulator;
|
||||
static CalibrationContext CalCtx;
|
||||
|
||||
void StartCalibration()
|
||||
{
|
||||
CalCtx.state = Begin;
|
||||
}
|
||||
|
||||
bool InitVR()
|
||||
{
|
||||
auto initError = vr::VRInitError_None;
|
||||
vr::VR_Init(&initError, vr::VRApplication_Other);
|
||||
if (initError != vr::VRInitError_None)
|
||||
{
|
||||
auto error = vr::VR_GetVRInitErrorAsEnglishDescription(initError);
|
||||
std::cerr << "OpenVR error: " << error << std::endl;
|
||||
wchar_t message[1024];
|
||||
swprintf(message, 1024, L"%hs", error);
|
||||
MessageBox(nullptr, message, L"Failed to initialize OpenVR", 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version))
|
||||
{
|
||||
MessageBox(nullptr, L"Outdated IVRSystem_Version", L"Failed to initialize OpenVR", 0);
|
||||
return false;
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version))
|
||||
{
|
||||
MessageBox(nullptr, L"Outdated IVRSettings_Version", L"Failed to initialize OpenVR", 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
InputEmulator.connect();
|
||||
return true;
|
||||
Driver.Connect();
|
||||
}
|
||||
|
||||
struct Pose
|
||||
@@ -165,7 +111,9 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
deltas.push_back(delta);
|
||||
}
|
||||
}
|
||||
printf("got %zd samples with %zd delta samples\n", samples.size(), deltas.size());
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Got %zd samples with %zd delta samples\n", samples.size(), deltas.size());
|
||||
CalCtx.Message(buf);
|
||||
|
||||
// Kabsch algorithm
|
||||
|
||||
@@ -206,7 +154,8 @@ Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
|
||||
Eigen::Vector3d euler = rot.eulerAngles(2, 1, 0) * 180.0 / EIGEN_PI;
|
||||
|
||||
printf("rotation yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[2], euler[0]);
|
||||
snprintf(buf, sizeof buf, "Calibrated rotation: yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[2], euler[0]);
|
||||
CalCtx.Message(buf);
|
||||
return euler;
|
||||
}
|
||||
|
||||
@@ -247,24 +196,34 @@ Eigen::Vector3d CalibrateTranslation(const std::vector<Sample> &samples)
|
||||
Eigen::Vector3d trans = coefficients.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(constants);
|
||||
auto transcm = trans * 100.0;
|
||||
|
||||
printf("translation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Calibrated translation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
|
||||
CalCtx.Message(buf);
|
||||
return transcm;
|
||||
}
|
||||
|
||||
Sample CollectSample(const CalibrationContext &ctx)
|
||||
{
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount], reference, target;
|
||||
vr::TrackedDevicePose_t reference, target;
|
||||
reference.bPoseIsValid = false;
|
||||
target.bPoseIsValid = false;
|
||||
|
||||
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
|
||||
reference = ctx.devicePoses[ctx.referenceID];
|
||||
target = ctx.devicePoses[ctx.targetID];
|
||||
|
||||
reference = devicePoses[ctx.referenceID];
|
||||
target = devicePoses[ctx.targetID];
|
||||
|
||||
if (!reference.bPoseIsValid || !target.bPoseIsValid)
|
||||
bool ok = true;
|
||||
if (!reference.bPoseIsValid)
|
||||
{
|
||||
printf("invalid pose for:%s%s\n", reference.bPoseIsValid ? "" : " <left controller>", target.bPoseIsValid ? "" : " <vive tracker>");
|
||||
CalCtx.Message("Reference device is not tracking\n"); ok = false;
|
||||
}
|
||||
if (!target.bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Target device is not tracking\n"); ok = false;
|
||||
}
|
||||
if (!ok)
|
||||
{
|
||||
CalCtx.Message("Aborting calibration!\n");
|
||||
CalCtx.state = CalibrationState::None;
|
||||
return Sample();
|
||||
}
|
||||
|
||||
@@ -274,104 +233,6 @@ Sample CollectSample(const CalibrationContext &ctx)
|
||||
);
|
||||
}
|
||||
|
||||
bool PickDevices(CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
auto deviceClass = vr::VRSystem()->GetTrackedDeviceClass(id);
|
||||
if (deviceClass == vr::TrackedDeviceClass_Invalid)
|
||||
continue;
|
||||
|
||||
if (devicePoses[id].bPoseIsValid)
|
||||
{
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_SerialNumber_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
if (err == vr::TrackedProp_Success)
|
||||
{
|
||||
std::string serial(buffer);
|
||||
//printf("got valid pose for id=%d serial=%s\n", id, serial.c_str());
|
||||
|
||||
if (EndsWith(serial, "_Controller_Left"))
|
||||
{
|
||||
ctx.referenceID = id;
|
||||
}
|
||||
else if (StartsWith(serial, "LHR-"))
|
||||
{
|
||||
ctx.targetID = id;
|
||||
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
if (err == vr::TrackedProp_Success)
|
||||
{
|
||||
ctx.calibratedTrackingSystem = std::string(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("failed to get tracking system name for %s\n", serial.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("got valid pose for id=%d serial=<unknown>\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.referenceID == -1 || ctx.targetID == -1)
|
||||
{
|
||||
printf("missing devices:%s%s\n", ctx.referenceID == -1 ? "" : " <left controller>", ctx.targetID == -1 ? "" : " <vive tracker>");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ifstream file("openvr_space_calibration.txt");
|
||||
ctx.profileLoaded = true;
|
||||
ctx.validProfile = false;
|
||||
|
||||
if (!file.good())
|
||||
return;
|
||||
|
||||
file
|
||||
>> ctx.calibratedTrackingSystem
|
||||
>> ctx.calibratedRotation(1) // yaw
|
||||
>> ctx.calibratedRotation(2) // pitch
|
||||
>> ctx.calibratedRotation(0) // roll
|
||||
>> ctx.calibratedTranslation(0) // x
|
||||
>> ctx.calibratedTranslation(1) // y
|
||||
>> ctx.calibratedTranslation(2); // z
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
void SaveProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ofstream file("openvr_space_calibration.txt");
|
||||
|
||||
file
|
||||
<< ctx.calibratedTrackingSystem << std::endl
|
||||
<< std::setprecision(std::numeric_limits<double>::digits10 + 1)
|
||||
<< ctx.calibratedRotation(1) << " " // yaw
|
||||
<< ctx.calibratedRotation(2) << " " // pitch
|
||||
<< ctx.calibratedRotation(0) << std::endl // roll
|
||||
<< ctx.calibratedTranslation(0) << " " // x
|
||||
<< ctx.calibratedTranslation(1) << " " // y
|
||||
<< ctx.calibratedTranslation(2) << std::endl; //z
|
||||
|
||||
ctx.profileLoaded = true;
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
vr::HmdQuaternion_t VRRotationQuat(Eigen::Vector3d eulerdeg)
|
||||
{
|
||||
auto euler = eulerdeg * EIGEN_PI / 180.0;
|
||||
@@ -399,13 +260,23 @@ vr::HmdVector3d_t VRTranslationVec(Eigen::Vector3d transcm)
|
||||
return vrTrans;
|
||||
}
|
||||
|
||||
void ScanAndApplyProfile(const CalibrationContext &ctx)
|
||||
void ResetAndDisableOffsets(uint32_t id)
|
||||
{
|
||||
vr::HmdVector3d_t zeroV;
|
||||
zeroV.v[0] = zeroV.v[1] = zeroV.v[2] = 0;
|
||||
|
||||
vr::HmdQuaternion_t zeroQ;
|
||||
zeroQ.x = 0; zeroQ.y = 0; zeroQ.z = 0; zeroQ.w = 1;
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { id, false, zeroV, zeroQ };
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, devicePoses, vr::k_unMaxTrackedDeviceCount);
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
auto deviceClass = vr::VRSystem()->GetTrackedDeviceClass(id);
|
||||
@@ -417,98 +288,153 @@ void ScanAndApplyProfile(const CalibrationContext &ctx)
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
auto universeId = vr::VRSystem()->GetUint64TrackedDeviceProperty(id, vr::Prop_CurrentUniverseId_Uint64, &err);
|
||||
printf("uid %d err %d\n", universeId, err);
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}*/
|
||||
|
||||
if (!ctx.validProfile)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
{
|
||||
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("REF %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
if (err != vr::TrackedProp_Success)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string trackingSystem(buffer);
|
||||
|
||||
if (trackingSystem != ctx.calibratedTrackingSystem)
|
||||
if (trackingSystem != ctx.targetTrackingSystem)
|
||||
{
|
||||
ResetAndDisableOffsets(id);
|
||||
continue;
|
||||
|
||||
if (deviceClass == vr::TrackedDeviceClass_TrackingReference)
|
||||
{
|
||||
// TODO(pushrax): detect zero reference switches and adjust calibration automatically
|
||||
//auto p = devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("%d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
}
|
||||
else
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = {
|
||||
id,
|
||||
true,
|
||||
VRTranslationVec(ctx.calibratedTranslation),
|
||||
VRRotationQuat(ctx.calibratedRotation)
|
||||
};
|
||||
Driver.SendBlocking(req);
|
||||
}
|
||||
|
||||
if (ctx.chaperone.valid && ctx.chaperone.autoApply)
|
||||
{
|
||||
uint32_t quadCount = 0;
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(nullptr, &quadCount);
|
||||
|
||||
// Heuristic: when SteamVR resets to a blank-ish chaperone, it uses empty geometry,
|
||||
// but manual adjustments (e.g. via a play space mover) will not touch geometry.
|
||||
if (quadCount != ctx.chaperone.geometry.size())
|
||||
{
|
||||
//printf("setting calibration for %d (%s)\n", id, buffer);
|
||||
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(id, vrRotQuat);
|
||||
|
||||
auto vrTransVec = VRTranslationVec(ctx.calibratedTranslation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(id, vrTransVec);
|
||||
|
||||
InputEmulator.enableDeviceOffsets(id, true);
|
||||
ApplyChaperoneBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAndDisableOffsets(uint32_t id)
|
||||
void StartCalibration()
|
||||
{
|
||||
vr::HmdVector3d_t zeroV;
|
||||
zeroV.v[0] = zeroV.v[1] = zeroV.v[2] = 0;
|
||||
|
||||
vr::HmdQuaternion_t zeroQ;
|
||||
zeroQ.x = 0; zeroQ.y = 0; zeroQ.z = 0; zeroQ.w = 1;
|
||||
|
||||
InputEmulator.setWorldFromDriverRotationOffset(id, zeroQ);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(id, zeroV);
|
||||
InputEmulator.enableDeviceOffsets(id, false);
|
||||
CalCtx.state = CalibrationState::Begin;
|
||||
CalCtx.wantedUpdateInterval = 0.0;
|
||||
CalCtx.messages = "";
|
||||
}
|
||||
|
||||
void CalibrationTick()
|
||||
void CalibrationTick(double time)
|
||||
{
|
||||
if (!vr::VRSystem())
|
||||
return;
|
||||
|
||||
auto &ctx = CalCtx;
|
||||
if ((time - ctx.timeLastTick) < 0.05)
|
||||
return;
|
||||
|
||||
if (ctx.state == None)
|
||||
ctx.timeLastTick = time;
|
||||
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.0f, ctx.devicePoses, vr::k_unMaxTrackedDeviceCount);
|
||||
|
||||
if (ctx.state == CalibrationState::None)
|
||||
{
|
||||
if (!ctx.profileLoaded)
|
||||
{
|
||||
LoadProfile(ctx);
|
||||
}
|
||||
else if (!ctx.validProfile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ctx.wantedUpdateInterval = 1.0;
|
||||
|
||||
if (ctx.ticksSinceScan == 0)
|
||||
if ((time - ctx.timeLastScan) >= 1.0)
|
||||
{
|
||||
ScanAndApplyProfile(ctx);
|
||||
ctx.timeLastScan = time;
|
||||
}
|
||||
ctx.ticksSinceScan = (ctx.ticksSinceScan + 1) % 40;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.state == Begin)
|
||||
if (ctx.state == CalibrationState::Editing)
|
||||
{
|
||||
ctx.referenceID = -1;
|
||||
ctx.targetID = -1;
|
||||
if (PickDevices(ctx))
|
||||
ctx.wantedUpdateInterval = 0.1;
|
||||
|
||||
if ((time - ctx.timeLastScan) >= 0.1)
|
||||
{
|
||||
ResetAndDisableOffsets(ctx.targetID);
|
||||
ctx.state = Rotation;
|
||||
printf("starting calibration, referenceID=%d targetID=%d\n", ctx.referenceID, ctx.targetID);
|
||||
ScanAndApplyProfile(ctx);
|
||||
ctx.timeLastScan = time;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.state == CalibrationState::Begin)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (ctx.referenceID == -1)
|
||||
{
|
||||
CalCtx.Message("Missing reference device\n"); ok = false;
|
||||
}
|
||||
else if (!ctx.devicePoses[ctx.referenceID].bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Reference device is not tracking\n"); ok = false;
|
||||
}
|
||||
|
||||
if (ctx.targetID == -1)
|
||||
{
|
||||
CalCtx.Message("Missing target device\n"); ok = false;
|
||||
}
|
||||
else if (!ctx.devicePoses[ctx.targetID].bPoseIsValid)
|
||||
{
|
||||
CalCtx.Message("Target device is not tracking\n"); ok = false;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
ctx.state = CalibrationState::None;
|
||||
CalCtx.Message("Aborting calibration!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ResetAndDisableOffsets(ctx.targetID);
|
||||
ctx.state = CalibrationState::Rotation;
|
||||
ctx.wantedUpdateInterval = 0.0;
|
||||
|
||||
char buf[256];
|
||||
snprintf(buf, sizeof buf, "Starting calibration, referenceID=%d targetID=%d\n", ctx.referenceID, ctx.targetID);
|
||||
CalCtx.Message(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
auto sample = CollectSample(ctx);
|
||||
if (!sample.valid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
printf(".");
|
||||
CalCtx.Message(".");
|
||||
|
||||
const int totalSamples = 100;
|
||||
static std::vector<Sample> samples;
|
||||
@@ -516,30 +442,58 @@ void CalibrationTick()
|
||||
|
||||
if (samples.size() == totalSamples)
|
||||
{
|
||||
printf("\n");
|
||||
if (ctx.state == Rotation)
|
||||
CalCtx.Message("\n");
|
||||
if (ctx.state == CalibrationState::Rotation)
|
||||
{
|
||||
ctx.calibratedRotation = CalibrateRotation(samples);
|
||||
|
||||
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(ctx.targetID, vrRotQuat);
|
||||
InputEmulator.enableDeviceOffsets(ctx.targetID, true);
|
||||
|
||||
ctx.state = Translation;
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { ctx.targetID, true, vrRotQuat };
|
||||
Driver.SendBlocking(req);
|
||||
|
||||
ctx.state = CalibrationState::Translation;
|
||||
}
|
||||
else if (ctx.state == Translation)
|
||||
else if (ctx.state == CalibrationState::Translation)
|
||||
{
|
||||
ctx.calibratedTranslation = CalibrateTranslation(samples);
|
||||
|
||||
auto vrTrans = VRTranslationVec(ctx.calibratedTranslation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(ctx.targetID, vrTrans);
|
||||
|
||||
protocol::Request req(protocol::RequestSetDeviceTransform);
|
||||
req.setDeviceTransform = { ctx.targetID, true, vrTrans };
|
||||
Driver.SendBlocking(req);
|
||||
|
||||
SaveProfile(ctx);
|
||||
printf("finished calibration, profile saved\n");
|
||||
CalCtx.Message("Finished calibration, profile saved\n");
|
||||
|
||||
ctx.state = None;
|
||||
ctx.state = CalibrationState::None;
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadChaperoneBounds()
|
||||
{
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
|
||||
uint32_t quadCount = 0;
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(nullptr, &quadCount);
|
||||
|
||||
CalCtx.chaperone.geometry.resize(quadCount);
|
||||
vr::VRChaperoneSetup()->GetLiveCollisionBoundsInfo(&CalCtx.chaperone.geometry[0], &quadCount);
|
||||
vr::VRChaperoneSetup()->GetWorkingStandingZeroPoseToRawTrackingPose(&CalCtx.chaperone.standingCenter);
|
||||
vr::VRChaperoneSetup()->GetWorkingPlayAreaSize(&CalCtx.chaperone.playSpaceSize.v[0], &CalCtx.chaperone.playSpaceSize.v[1]);
|
||||
CalCtx.chaperone.valid = true;
|
||||
}
|
||||
|
||||
void ApplyChaperoneBounds()
|
||||
{
|
||||
vr::VRChaperoneSetup()->RevertWorkingCopy();
|
||||
vr::VRChaperoneSetup()->SetWorkingCollisionBoundsInfo(&CalCtx.chaperone.geometry[0], CalCtx.chaperone.geometry.size());
|
||||
vr::VRChaperoneSetup()->SetWorkingStandingZeroPoseToRawTrackingPose(&CalCtx.chaperone.standingCenter);
|
||||
vr::VRChaperoneSetup()->SetWorkingPlayAreaSize(CalCtx.chaperone.playSpaceSize.v[0], CalCtx.chaperone.playSpaceSize.v[1]);
|
||||
vr::VRChaperoneSetup()->CommitWorkingCopy(vr::EChaperoneConfigFile_Live);
|
||||
}
|
||||
@@ -1,5 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
bool InitVR();
|
||||
#include <Eigen/Core>
|
||||
#include <openvr.h>
|
||||
#include <vector>
|
||||
|
||||
enum class CalibrationState
|
||||
{
|
||||
None,
|
||||
Begin,
|
||||
Rotation,
|
||||
Translation,
|
||||
Editing,
|
||||
};
|
||||
|
||||
struct CalibrationContext
|
||||
{
|
||||
CalibrationState state = CalibrationState::None;
|
||||
uint32_t referenceID, targetID;
|
||||
|
||||
Eigen::Vector3d calibratedRotation;
|
||||
Eigen::Vector3d calibratedTranslation;
|
||||
|
||||
std::string referenceTrackingSystem;
|
||||
std::string targetTrackingSystem;
|
||||
|
||||
bool validProfile = false;
|
||||
double timeLastTick = 0, timeLastScan = 0;
|
||||
double wantedUpdateInterval = 1.0;
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
|
||||
struct Chaperone
|
||||
{
|
||||
bool valid = false;
|
||||
bool autoApply = true;
|
||||
std::vector<vr::HmdQuad_t> geometry;
|
||||
vr::HmdMatrix34_t standingCenter;
|
||||
vr::HmdVector2_t playSpaceSize;
|
||||
} chaperone;
|
||||
|
||||
std::string messages;
|
||||
|
||||
void Message(const std::string &msg)
|
||||
{
|
||||
messages += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
};
|
||||
|
||||
extern CalibrationContext CalCtx;
|
||||
|
||||
void InitCalibrator();
|
||||
void CalibrationTick(double time);
|
||||
void StartCalibration();
|
||||
void CalibrationTick();
|
||||
void LoadChaperoneBounds();
|
||||
void ApplyChaperoneBounds();
|
||||
@@ -0,0 +1,237 @@
|
||||
#include "stdafx.h"
|
||||
#include "Configuration.h"
|
||||
|
||||
#include <picojson.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
|
||||
static void UpgradeProfileV1(CalibrationContext &ctx);
|
||||
static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream);
|
||||
|
||||
static std::string ConfigFileName()
|
||||
{
|
||||
std::string vrRuntimeConfigName = vr::VR_RuntimePath();
|
||||
return vrRuntimeConfigName + "\\..\\..\\..\\config\\01spacecalibrator\\calibration.json";
|
||||
}
|
||||
|
||||
picojson::array FloatArray(const float *buf, int numFloats)
|
||||
{
|
||||
picojson::array arr;
|
||||
|
||||
for (int i = 0; i < numFloats; i++)
|
||||
arr.push_back(picojson::value(double(buf[i])));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
void LoadFloatArray(const picojson::value &obj, float *buf, int numFloats)
|
||||
{
|
||||
if (!obj.is<picojson::array>())
|
||||
throw std::runtime_error("expected array, got " + obj.to_str());
|
||||
|
||||
auto &arr = obj.get<picojson::array>();
|
||||
if (arr.size() != numFloats)
|
||||
throw std::runtime_error("wrong buffer size");
|
||||
|
||||
for (int i = 0; i < numFloats; i++)
|
||||
buf[i] = (float) arr[i].get<double>();
|
||||
}
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx)
|
||||
{
|
||||
ctx.validProfile = false;
|
||||
|
||||
std::ifstream file(ConfigFileName());
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout << "Profile missing, trying fallback path" << std::endl;
|
||||
// Fallback to working directory, which was the default for a long time.
|
||||
file = std::ifstream("openvr_space_calibration.json");
|
||||
}
|
||||
|
||||
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout << "Fallback profile missing, trying V1 path" << std::endl;
|
||||
UpgradeProfileV1(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ParseProfileV2(ctx, file);
|
||||
std::cout << "Loaded profile" << std::endl;
|
||||
}
|
||||
catch (const std::runtime_error &e)
|
||||
{
|
||||
std::cerr << "Error loading profile: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
static void ParseProfileV2(CalibrationContext &ctx, std::istream &stream)
|
||||
{
|
||||
picojson::value v;
|
||||
std::string err = picojson::parse(v, stream);
|
||||
if (!err.empty())
|
||||
throw std::runtime_error(err);
|
||||
|
||||
auto arr = v.get<picojson::array>();
|
||||
if (arr.size() < 1)
|
||||
throw std::runtime_error("no profiles in file");
|
||||
|
||||
auto obj = arr[0].get<picojson::object>();
|
||||
|
||||
ctx.referenceTrackingSystem = obj["reference_tracking_system"].get<std::string>();
|
||||
ctx.targetTrackingSystem = obj["target_tracking_system"].get<std::string>();
|
||||
ctx.calibratedRotation(0) = obj["roll"].get<double>();
|
||||
ctx.calibratedRotation(1) = obj["yaw"].get<double>();
|
||||
ctx.calibratedRotation(2) = obj["pitch"].get<double>();
|
||||
ctx.calibratedTranslation(0) = obj["x"].get<double>();
|
||||
ctx.calibratedTranslation(1) = obj["y"].get<double>();
|
||||
ctx.calibratedTranslation(2) = obj["z"].get<double>();
|
||||
|
||||
if (obj["chaperone"].is<picojson::object>())
|
||||
{
|
||||
auto chaperone = obj["chaperone"].get<picojson::object>();
|
||||
ctx.chaperone.autoApply = chaperone["auto_apply"].get<bool>();
|
||||
|
||||
LoadFloatArray(chaperone["play_space_size"], ctx.chaperone.playSpaceSize.v, 2);
|
||||
|
||||
LoadFloatArray(
|
||||
chaperone["standing_center"],
|
||||
(float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter) / sizeof(float)
|
||||
);
|
||||
|
||||
if (!chaperone["geometry"].is<picojson::array>())
|
||||
throw std::runtime_error("chaperone geometry is not an array");
|
||||
|
||||
auto &geometry = chaperone["geometry"].get<picojson::array>();
|
||||
|
||||
if (geometry.size() > 0)
|
||||
{
|
||||
ctx.chaperone.geometry.resize(geometry.size() * sizeof(float) / sizeof(ctx.chaperone.geometry[0]));
|
||||
LoadFloatArray(chaperone["geometry"], (float *) ctx.chaperone.geometry.data(), geometry.size());
|
||||
|
||||
ctx.chaperone.valid = true;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
void SaveProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::cout << "Saving profile to " << ConfigFileName() << std::endl;
|
||||
|
||||
std::ofstream file(ConfigFileName());
|
||||
|
||||
picojson::object profile;
|
||||
profile["reference_tracking_system"].set<std::string>(ctx.referenceTrackingSystem);
|
||||
profile["target_tracking_system"].set<std::string>(ctx.targetTrackingSystem);
|
||||
profile["roll"].set<double>(ctx.calibratedRotation(0));
|
||||
profile["yaw"].set<double>(ctx.calibratedRotation(1));
|
||||
profile["pitch"].set<double>(ctx.calibratedRotation(2));
|
||||
profile["x"].set<double>(ctx.calibratedTranslation(0));
|
||||
profile["y"].set<double>(ctx.calibratedTranslation(1));
|
||||
profile["z"].set<double>(ctx.calibratedTranslation(2));
|
||||
|
||||
if (ctx.chaperone.valid)
|
||||
{
|
||||
picojson::object chaperone;
|
||||
chaperone["auto_apply"].set<bool>(ctx.chaperone.autoApply);
|
||||
chaperone["play_space_size"].set<picojson::array>(FloatArray(ctx.chaperone.playSpaceSize.v, 2));
|
||||
|
||||
chaperone["standing_center"].set<picojson::array>(
|
||||
FloatArray((float *) ctx.chaperone.standingCenter.m,
|
||||
sizeof(ctx.chaperone.standingCenter) / sizeof(float)
|
||||
));
|
||||
|
||||
chaperone["geometry"].set<picojson::array>(
|
||||
FloatArray((float *) ctx.chaperone.geometry.data(),
|
||||
sizeof(ctx.chaperone.geometry[0]) / sizeof(float) * ctx.chaperone.geometry.size()
|
||||
));
|
||||
|
||||
profile["chaperone"].set<picojson::object>(chaperone);
|
||||
}
|
||||
|
||||
picojson::value profileV;
|
||||
profileV.set<picojson::object>(profile);
|
||||
|
||||
picojson::array profiles;
|
||||
profiles.push_back(profileV);
|
||||
|
||||
picojson::value profilesV;
|
||||
profilesV.set<picojson::array>(profiles);
|
||||
|
||||
file << profilesV.serialize(true);
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
static void UpgradeProfileV1(CalibrationContext &ctx)
|
||||
{
|
||||
std::ifstream file("openvr_space_calibration.txt");
|
||||
ctx.validProfile = false;
|
||||
|
||||
if (!file.good())
|
||||
return;
|
||||
|
||||
file
|
||||
>> ctx.targetTrackingSystem
|
||||
>> ctx.calibratedRotation(1) // yaw
|
||||
>> ctx.calibratedRotation(2) // pitch
|
||||
>> ctx.calibratedRotation(0) // roll
|
||||
>> ctx.calibratedTranslation(0) // x
|
||||
>> ctx.calibratedTranslation(1) // y
|
||||
>> ctx.calibratedTranslation(2); // z
|
||||
|
||||
ctx.validProfile = true;
|
||||
|
||||
SaveProfile(ctx);
|
||||
|
||||
file.close();
|
||||
std::remove("openvr_space_calibration.txt");
|
||||
}
|
||||
|
||||
void WriteActivateMultipleDriversToConfig()
|
||||
{
|
||||
std::string configPath = vr::VR_RuntimePath();
|
||||
configPath += "\\..\\..\\..\\config\\steamvr.vrsettings";
|
||||
|
||||
std::ifstream ifile(configPath);
|
||||
if (!ifile.good())
|
||||
throw std::runtime_error("failed to read steamvr.vrsettings");
|
||||
|
||||
picojson::value v;
|
||||
std::string err = picojson::parse(v, ifile);
|
||||
if (!err.empty())
|
||||
throw std::runtime_error(err);
|
||||
|
||||
ifile.close();
|
||||
|
||||
if (!v.is<picojson::object>())
|
||||
throw std::runtime_error("steamvr.vrsettings is empty");
|
||||
|
||||
auto &root = v.get<picojson::object>();
|
||||
|
||||
if (!root["steamvr"].is<picojson::object>())
|
||||
throw std::runtime_error("steamvr.vrsettings is missing \"steamvr\" key");
|
||||
|
||||
auto &steamvr = root["steamvr"].get<picojson::object>();
|
||||
|
||||
const bool tru = true; // MSVC picks the wrong specialization when passing a literal...
|
||||
steamvr["activateMultipleDrivers"].set<bool>(tru);
|
||||
|
||||
std::ofstream ofile(configPath);
|
||||
if (!ofile.good())
|
||||
throw std::runtime_error("failed to write steamvr.vrsettings");
|
||||
|
||||
v.serialize(std::ostream_iterator<char>(ofile), true);
|
||||
|
||||
std::cout << "Successfully set activateMultipleDrivers to true" << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Calibration.h"
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx);
|
||||
void SaveProfile(CalibrationContext &ctx);
|
||||
void WriteActivateMultipleDriversToConfig();
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
const unsigned int DroidSans_compressed_size = 134345;
|
||||
extern const unsigned int DroidSans_compressed_data[134348 / 4];
|
||||
@@ -0,0 +1,93 @@
|
||||
#include "stdafx.h"
|
||||
#include "IPCClient.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
static std::string LastErrorString(DWORD lastError)
|
||||
{
|
||||
LPSTR buffer = nullptr;
|
||||
size_t size = FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, lastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buffer, 0, NULL
|
||||
);
|
||||
|
||||
std::string message(buffer, size);
|
||||
LocalFree(buffer);
|
||||
return message;
|
||||
}
|
||||
|
||||
IPCClient::~IPCClient()
|
||||
{
|
||||
if (pipe && pipe != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(pipe);
|
||||
}
|
||||
|
||||
void IPCClient::Connect()
|
||||
{
|
||||
LPTSTR pipeName = TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME);
|
||||
|
||||
WaitNamedPipe(pipeName, 1000);
|
||||
pipe = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
|
||||
if (pipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
throw std::runtime_error("Space Calibrator driver unavailable, is SteamVR running and not in safe mode? Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
|
||||
DWORD mode = PIPE_READMODE_MESSAGE;
|
||||
if (!SetNamedPipeHandleState(pipe, &mode, 0, 0))
|
||||
{
|
||||
throw std::runtime_error("Couldn't set pipe mode. Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
|
||||
auto response = SendBlocking(protocol::Request(protocol::RequestHandshake));
|
||||
if (response.type != protocol::ResponseHandshake || response.protocol.version != protocol::Version)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Incorrect driver version installed, try reinstalling OpenVR-SpaceCalibrator. (Client: " +
|
||||
std::to_string(protocol::Version) +
|
||||
", Driver: " +
|
||||
std::to_string(response.protocol.version) +
|
||||
")"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protocol::Response IPCClient::SendBlocking(const protocol::Request &request)
|
||||
{
|
||||
Send(request);
|
||||
return Receive();
|
||||
}
|
||||
|
||||
void IPCClient::Send(const protocol::Request &request)
|
||||
{
|
||||
DWORD bytesWritten;
|
||||
BOOL success = WriteFile(pipe, &request, sizeof request, &bytesWritten, 0);
|
||||
if (!success)
|
||||
{
|
||||
throw std::runtime_error("Error writing IPC request. Error: " + LastErrorString(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
protocol::Response IPCClient::Receive()
|
||||
{
|
||||
protocol::Response response(protocol::ResponseInvalid);
|
||||
DWORD bytesRead;
|
||||
|
||||
BOOL success = ReadFile(pipe, &response, sizeof response, &bytesRead, 0);
|
||||
if (!success)
|
||||
{
|
||||
DWORD lastError = GetLastError();
|
||||
if (lastError != ERROR_MORE_DATA)
|
||||
{
|
||||
throw std::runtime_error("Error reading IPC response. Error: " + LastErrorString(lastError));
|
||||
}
|
||||
}
|
||||
|
||||
if (bytesRead != sizeof response)
|
||||
{
|
||||
throw std::runtime_error("Invalid IPC response with size " + std::to_string(bytesRead));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Protocol.h"
|
||||
|
||||
class IPCClient
|
||||
{
|
||||
public:
|
||||
~IPCClient();
|
||||
|
||||
void Connect();
|
||||
protocol::Response SendBlocking(const protocol::Request &request);
|
||||
|
||||
void Send(const protocol::Request &request);
|
||||
protocol::Response Receive();
|
||||
|
||||
private:
|
||||
HANDLE pipe = INVALID_HANDLE_VALUE;
|
||||
};
|
||||
@@ -1,20 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "OpenVR-SpaceCalibrator.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.h"
|
||||
#include "EmbeddedFiles.h"
|
||||
#include "UserInterface.h"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include <imgui/imgui_impl_glfw.h>
|
||||
#include <imgui/imgui_impl_opengl3.h>
|
||||
#include <GL/gl3w.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <openvr.h>
|
||||
#include <direct.h>
|
||||
|
||||
#pragma comment(linker,"\"/manifestdependency:type='win32' \
|
||||
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
|
||||
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
|
||||
#define MAX_LOADSTRING 100
|
||||
|
||||
HINSTANCE hInst;
|
||||
WCHAR szTitle[MAX_LOADSTRING];
|
||||
WCHAR szWindowClass[MAX_LOADSTRING];
|
||||
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||
BOOL InitInstance(HINSTANCE, int);
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
#define OPENVR_APPLICATION_KEY "pushrax.SpaceCalibrator"
|
||||
|
||||
void CreateConsole()
|
||||
{
|
||||
@@ -30,112 +32,408 @@ void CreateConsole()
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWErrorCallback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
|
||||
static void HandleCommandLine(LPWSTR lpCmdLine);
|
||||
|
||||
static GLFWwindow *glfwWindow = nullptr;
|
||||
static vr::VROverlayHandle_t overlayMainHandle = 0, overlayThumbnailHandle = 0;
|
||||
static GLuint fboHandle = 0, fboTextureHandle = 0;
|
||||
static int fboTextureWidth = 0, fboTextureHeight = 0;
|
||||
|
||||
static char cwd[MAX_PATH];
|
||||
|
||||
void CreateGLFWWindow()
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_RESIZABLE, false);
|
||||
|
||||
fboTextureWidth = 1200;
|
||||
fboTextureHeight = 800;
|
||||
|
||||
glfwWindow = glfwCreateWindow(fboTextureWidth, fboTextureHeight, "OpenVR-SpaceCalibrator", NULL, NULL);
|
||||
if (!glfwWindow)
|
||||
throw std::runtime_error("Failed to create window");
|
||||
|
||||
glfwMakeContextCurrent(glfwWindow);
|
||||
glfwSwapInterval(1);
|
||||
gl3wInit();
|
||||
|
||||
glfwIconifyWindow(glfwWindow);
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
io.IniFilename = nullptr;
|
||||
io.Fonts->AddFontFromMemoryCompressedTTF(DroidSans_compressed_data, DroidSans_compressed_size, 24.0f);
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(glfwWindow, true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330");
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
glGenTextures(1, &fboTextureHandle);
|
||||
glBindTexture(GL_TEXTURE_2D, fboTextureHandle);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fboTextureWidth, fboTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenFramebuffers(1, &fboHandle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
|
||||
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fboTextureHandle, 0);
|
||||
|
||||
GLenum drawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
|
||||
glDrawBuffers(1, drawBuffers);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
{
|
||||
throw std::runtime_error("OpenGL framebuffer incomplete");
|
||||
}
|
||||
}
|
||||
|
||||
void TryCreateVROverlay()
|
||||
{
|
||||
if (overlayMainHandle || !vr::VROverlay())
|
||||
return;
|
||||
|
||||
vr::VROverlayError error = vr::VROverlay()->CreateDashboardOverlay(
|
||||
"pushrax.SpaceCalibrator", "Space Cal",
|
||||
&overlayMainHandle, &overlayThumbnailHandle
|
||||
);
|
||||
|
||||
if (error == vr::VROverlayError_KeyInUse)
|
||||
{
|
||||
throw std::runtime_error("Another instance of OpenVR Space Calibrator is already running");
|
||||
}
|
||||
else if (error != vr::VROverlayError_None)
|
||||
{
|
||||
throw std::runtime_error("Error creating VR overlay: " + std::string(vr::VROverlay()->GetOverlayErrorNameFromEnum(error)));
|
||||
}
|
||||
|
||||
vr::VROverlay()->SetOverlayWidthInMeters(overlayMainHandle, 3.0f);
|
||||
vr::VROverlay()->SetOverlayInputMethod(overlayMainHandle, vr::VROverlayInputMethod_Mouse);
|
||||
vr::VROverlay()->SetOverlayFlag(overlayMainHandle, vr::VROverlayFlags_SendVRScrollEvents, true);
|
||||
|
||||
std::string iconPath = cwd;
|
||||
iconPath += "\\icon.png";
|
||||
vr::VROverlay()->SetOverlayFromFile(overlayThumbnailHandle, iconPath.c_str());
|
||||
}
|
||||
|
||||
void InitVR()
|
||||
{
|
||||
auto initError = vr::VRInitError_None;
|
||||
vr::VR_Init(&initError, vr::VRApplication_Other);
|
||||
if (initError != vr::VRInitError_None)
|
||||
{
|
||||
auto error = vr::VR_GetVRInitErrorAsEnglishDescription(initError);
|
||||
throw std::runtime_error("OpenVR error:" + std::string(error));
|
||||
}
|
||||
|
||||
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSystem_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSettings_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVROverlay_Version))
|
||||
{
|
||||
throw std::runtime_error("OpenVR error: Outdated IVROverlay_Version");
|
||||
}
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
{
|
||||
while (!glfwWindowShouldClose(glfwWindow))
|
||||
{
|
||||
TryCreateVROverlay();
|
||||
|
||||
double time = glfwGetTime();
|
||||
CalibrationTick(time);
|
||||
|
||||
bool dashboardVisible = false;
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(glfwWindow, &width, &height);
|
||||
|
||||
if (overlayMainHandle && vr::VROverlay())
|
||||
{
|
||||
auto &io = ImGui::GetIO();
|
||||
dashboardVisible = vr::VROverlay()->IsActiveDashboardOverlay(overlayMainHandle);
|
||||
|
||||
static bool keyboardOpen = false, keyboardJustClosed = false;
|
||||
|
||||
// After closing the keyboard, this code waits one frame for ImGui to pick up the new text from SetActiveText
|
||||
// before clearing the active widget. Then it waits another frame before allowing the keyboard to open again,
|
||||
// otherwise it will do so instantly since WantTextInput is still true on the second frame.
|
||||
if (keyboardJustClosed && keyboardOpen)
|
||||
{
|
||||
ImGui::ClearActiveID();
|
||||
keyboardOpen = false;
|
||||
}
|
||||
else if (keyboardJustClosed)
|
||||
{
|
||||
keyboardJustClosed = false;
|
||||
}
|
||||
else if (!io.WantTextInput)
|
||||
{
|
||||
// User might close the keyboard without hitting Done, so we unset the flag to allow it to open again.
|
||||
keyboardOpen = false;
|
||||
}
|
||||
else if (io.WantTextInput && !keyboardOpen && !keyboardJustClosed)
|
||||
{
|
||||
char buf[0x400];
|
||||
ImGui::GetActiveText(buf, sizeof buf);
|
||||
buf[0x3ff] = 0;
|
||||
|
||||
vr::VROverlay()->ShowKeyboardForOverlay(
|
||||
overlayMainHandle, vr::k_EGamepadTextInputModeNormal, vr::k_EGamepadTextInputLineModeSingleLine,
|
||||
"Space Calibrator Overlay", sizeof buf, buf, false, 0
|
||||
);
|
||||
keyboardOpen = true;
|
||||
}
|
||||
|
||||
vr::VREvent_t vrEvent;
|
||||
while (vr::VROverlay()->PollNextOverlayEvent(overlayMainHandle, &vrEvent, sizeof(vrEvent)))
|
||||
{
|
||||
switch (vrEvent.eventType) {
|
||||
case vr::VREvent_MouseMove:
|
||||
io.MousePos.x = vrEvent.data.mouse.x;
|
||||
io.MousePos.y = vrEvent.data.mouse.y;
|
||||
break;
|
||||
case vr::VREvent_MouseButtonDown:
|
||||
io.MouseDown[vrEvent.data.mouse.button == vr::VRMouseButton_Left ? 0 : 1] = true;
|
||||
break;
|
||||
case vr::VREvent_MouseButtonUp:
|
||||
io.MouseDown[vrEvent.data.mouse.button == vr::VRMouseButton_Left ? 0 : 1] = false;
|
||||
break;
|
||||
case vr::VREvent_Scroll:
|
||||
io.MouseWheelH += vrEvent.data.scroll.xdelta * 360.0f * 8.0f;
|
||||
io.MouseWheel += vrEvent.data.scroll.ydelta * 360.0f * 8.0f;
|
||||
break;
|
||||
case vr::VREvent_KeyboardDone: {
|
||||
char buf[0x400];
|
||||
vr::VROverlay()->GetKeyboardText(buf, sizeof buf);
|
||||
ImGui::SetActiveText(buf, sizeof buf);
|
||||
keyboardJustClosed = true;
|
||||
break;
|
||||
}
|
||||
case vr::VREvent_Quit:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::GetIO().DisplaySize = ImVec2((float) fboTextureWidth, (float) fboTextureHeight);
|
||||
|
||||
ImGui_ImplGlfw_SetReadMouseFromGlfw(!dashboardVisible);
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
BuildMainWindow(dashboardVisible);
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fboHandle);
|
||||
glViewport(0, 0, fboTextureWidth, fboTextureHeight);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (width && height)
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboHandle);
|
||||
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
glfwSwapBuffers(glfwWindow);
|
||||
}
|
||||
|
||||
if (dashboardVisible)
|
||||
{
|
||||
vr::Texture_t vrTex;
|
||||
vrTex.eType = vr::TextureType_OpenGL;
|
||||
vrTex.eColorSpace = vr::ColorSpace_Linear;
|
||||
|
||||
vrTex.handle = (void *)
|
||||
#if defined _WIN64 || defined _LP64
|
||||
(uint64_t)
|
||||
#endif
|
||||
fboTextureHandle;
|
||||
|
||||
vr::HmdVector2_t mouseScale = { (float) fboTextureWidth, (float) fboTextureHeight };
|
||||
|
||||
vr::VROverlay()->SetOverlayTexture(overlayMainHandle, &vrTex);
|
||||
vr::VROverlay()->SetOverlayMouseScale(overlayMainHandle, &mouseScale);
|
||||
}
|
||||
|
||||
const double dashboardInterval = 1.0 / 90.0; // fps
|
||||
double waitEventsTimeout = CalCtx.wantedUpdateInterval;
|
||||
|
||||
if (dashboardVisible && waitEventsTimeout > dashboardInterval)
|
||||
waitEventsTimeout = dashboardInterval;
|
||||
|
||||
glfwWaitEventsTimeout(waitEventsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hPrevInstance);
|
||||
UNREFERENCED_PARAMETER(lpCmdLine);
|
||||
_getcwd(cwd, MAX_PATH);
|
||||
HandleCommandLine(lpCmdLine);
|
||||
//CreateConsole();
|
||||
|
||||
if (!InitVR())
|
||||
return FALSE;
|
||||
|
||||
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
||||
LoadStringW(hInstance, IDC_OPENVRSPACECALIBRATOR, szWindowClass, MAX_LOADSTRING);
|
||||
MyRegisterClass(hInstance);
|
||||
|
||||
if (!InitInstance(hInstance, nCmdShow))
|
||||
return FALSE;
|
||||
|
||||
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_OPENVRSPACECALIBRATOR));
|
||||
MSG msg;
|
||||
|
||||
while (GetMessage(&msg, nullptr, 0, 0))
|
||||
if (!glfwInit())
|
||||
{
|
||||
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
MessageBox(nullptr, L"Failed to initialize GLFW", L"", 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int)msg.wParam;
|
||||
}
|
||||
glfwSetErrorCallback(GLFWErrorCallback);
|
||||
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance)
|
||||
{
|
||||
WNDCLASSEXW wcex;
|
||||
try {
|
||||
InitVR();
|
||||
CreateGLFWWindow();
|
||||
InitCalibrator();
|
||||
LoadProfile(CalCtx);
|
||||
RunLoop();
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
vr::VR_Shutdown();
|
||||
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_OPENVRSPACECALIBRATOR));
|
||||
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_OPENVRSPACECALIBRATOR);
|
||||
wcex.lpszClassName = szWindowClass;
|
||||
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
|
||||
if (fboHandle)
|
||||
glDeleteFramebuffers(1, &fboHandle);
|
||||
|
||||
return RegisterClassExW(&wcex);
|
||||
}
|
||||
if (fboTextureHandle)
|
||||
glDeleteTextures(1, &fboTextureHandle);
|
||||
|
||||
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
||||
{
|
||||
hInst = hInstance;
|
||||
|
||||
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 300, 200, nullptr, nullptr, hInstance, nullptr);
|
||||
|
||||
if (!hWnd)
|
||||
return FALSE;
|
||||
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
SetTimer(hWnd, 1337, 50, nullptr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define CAL_BTN_ID 1001
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
HFONT hFont;
|
||||
HWND button;
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
button = CreateWindow(L"button", L"Start Calibration", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
|
||||
40, 30, 200, 100, hWnd, (HMENU)CAL_BTN_ID, hInst, NULL);
|
||||
|
||||
hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
|
||||
SendMessage(button, WM_SETFONT, (WPARAM)hFont, true);
|
||||
break;
|
||||
case WM_TIMER:
|
||||
CalibrationTick();
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
if (wParam == CAL_BTN_ID)
|
||||
{
|
||||
CreateConsole();
|
||||
StartCalibration();
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
std::cerr << "Runtime error: " << e.what() << std::endl;
|
||||
wchar_t message[1024];
|
||||
swprintf(message, 1024, L"%hs", e.what());
|
||||
MessageBox(nullptr, message, L"Runtime Error", 0);
|
||||
}
|
||||
|
||||
if (glfwWindow)
|
||||
glfwDestroyWindow(glfwWindow);
|
||||
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void HandleCommandLine(LPWSTR lpCmdLine)
|
||||
{
|
||||
if (lstrcmp(lpCmdLine, L"-openvrpath") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
printf("%s", vr::VR_RuntimePath());
|
||||
vr::VR_Shutdown();
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-installmanifest") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
if (vr::VRApplications()->IsApplicationInstalled(OPENVR_APPLICATION_KEY))
|
||||
{
|
||||
char oldWd[MAX_PATH] = { 0 };
|
||||
auto vrAppErr = vr::VRApplicationError_None;
|
||||
vr::VRApplications()->GetApplicationPropertyString(OPENVR_APPLICATION_KEY, vr::VRApplicationProperty_WorkingDirectory_String, oldWd, MAX_PATH, &vrAppErr);
|
||||
if (vrAppErr != vr::VRApplicationError_None)
|
||||
{
|
||||
fprintf(stderr, "Failed to get old working dir, skipping removal: %s\n", vr::VRApplications()->GetApplicationsErrorNameFromEnum(vrAppErr));
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string manifestPath = oldWd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Removing old manifest path: " << manifestPath << std::endl;
|
||||
vr::VRApplications()->RemoveApplicationManifest(manifestPath.c_str());
|
||||
}
|
||||
}
|
||||
std::string manifestPath = cwd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Adding manifest path: " << manifestPath << std::endl;
|
||||
auto vrAppErr = vr::VRApplications()->AddApplicationManifest(manifestPath.c_str());
|
||||
if (vrAppErr != vr::VRApplicationError_None)
|
||||
{
|
||||
fprintf(stderr, "Failed to add manifest: %s\n", vr::VRApplications()->GetApplicationsErrorNameFromEnum(vrAppErr));
|
||||
}
|
||||
else
|
||||
{
|
||||
vr::VRApplications()->SetApplicationAutoLaunch(OPENVR_APPLICATION_KEY, true);
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-removemanifest") == 0)
|
||||
{
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
if (vr::VRApplications()->IsApplicationInstalled(OPENVR_APPLICATION_KEY))
|
||||
{
|
||||
std::string manifestPath = cwd;
|
||||
manifestPath += "\\manifest.vrmanifest";
|
||||
std::cout << "Removing manifest path: " << manifestPath << std::endl;
|
||||
vr::VRApplications()->RemoveApplicationManifest(manifestPath.c_str());
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
vr::VR_Shutdown();
|
||||
exit(-2);
|
||||
}
|
||||
else if (lstrcmp(lpCmdLine, L"-activatemultipledrivers") == 0)
|
||||
{
|
||||
int ret = -2;
|
||||
auto vrErr = vr::VRInitError_None;
|
||||
vr::VR_Init(&vrErr, vr::VRApplication_Utility);
|
||||
if (vrErr == vr::VRInitError_None)
|
||||
{
|
||||
try
|
||||
{
|
||||
WriteActivateMultipleDriversToConfig();
|
||||
ret = 0;
|
||||
}
|
||||
catch (std::runtime_error &e)
|
||||
{
|
||||
std::cerr << "Failed to set activateMultipleDrivers: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Failed to initialize OpenVR: %s\n", vr::VR_GetVRInitErrorAsEnglishDescription(vrErr));
|
||||
}
|
||||
vr::VR_Shutdown();
|
||||
exit(ret);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource.h"
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 70 KiB |
@@ -1,14 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
@@ -25,19 +17,6 @@
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
@@ -56,12 +35,6 @@
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
@@ -69,34 +42,12 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>..\lib\openvr\openvr_api.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\lib\boost_1_63_0</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
@@ -104,35 +55,15 @@
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\lib\gl3w\include;..\lib\glfw\include;..\lib\openvr;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\boost_1_63_0\lib64-msvc-14.0;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>..\lib\openvr\openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\lib\boost_1_63_0</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@@ -142,54 +73,65 @@
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>_SCL_SECURE_NO_WARNINGS;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\boost_1_63_0;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\lib\gl3w\include;..\lib\glfw\include;..\lib\openvr;..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\boost_1_63_0\lib64-msvc-14.0;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\lib\glfw\lib-vc2015;..\lib\openvr\lib\win64</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>opengl32.lib;glfw3.lib;openvr_api.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\ipc_protocol.h" />
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator.h" />
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator_types.h" />
|
||||
<ClInclude Include="Calibration.h" />
|
||||
<ClInclude Include="OpenVR-SpaceCalibrator.h" />
|
||||
<ClInclude Include="Resource.h" />
|
||||
<ClInclude Include="Configuration.h" />
|
||||
<ClInclude Include="EmbeddedFiles.h" />
|
||||
<ClInclude Include="IPCClient.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="UserInterface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\lib\lib_vrinputemulator\vrinputemulator.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
|
||||
<ClCompile Include="..\lib\gl3w\src\gl3w.c">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_demo.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_draw.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_impl_glfw.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_impl_opengl3.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Calibration.cpp" />
|
||||
<ClCompile Include="Configuration.cpp" />
|
||||
<ClCompile Include="EmbeddedFiles.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCClient.cpp" />
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\lib;..\lib\openvr;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc" />
|
||||
<ClCompile Include="UserInterface.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="OpenVR-SpaceCalibrator.ico" />
|
||||
<Image Include="small.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -13,9 +13,12 @@
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="ReadMe.txt" />
|
||||
<Filter Include="Source Files\ImGui">
|
||||
<UniqueIdentifier>{948e4c13-6f2b-44e3-a8b7-1a12c79aeeb7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\GL">
|
||||
<UniqueIdentifier>{d156ae5c-9fe6-41f0-a34e-333dc7a6b2f8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
@@ -24,22 +27,19 @@
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="OpenVR-SpaceCalibrator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Calibration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\ipc_protocol.h">
|
||||
<ClInclude Include="EmbeddedFiles.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator.h">
|
||||
<ClInclude Include="UserInterface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator_types.h">
|
||||
<ClInclude Include="Configuration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPCClient.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
@@ -47,20 +47,42 @@
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Calibration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\lib_vrinputemulator\vrinputemulator.cpp">
|
||||
<ClCompile Include="..\lib\imgui\imgui.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_demo.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_impl_glfw.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_impl_opengl3.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\gl3w\src\gl3w.c">
|
||||
<Filter>Source Files\GL</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\lib\imgui\imgui_draw.cpp">
|
||||
<Filter>Source Files\ImGui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EmbeddedFiles.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UserInterface.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Configuration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCClient.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OpenVR-SpaceCalibrator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="small.ico">
|
||||
@@ -70,4 +92,9 @@
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,453 @@
|
||||
#include "stdafx.h"
|
||||
#include "UserInterface.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.h"
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#define VERSION_STRING "0.8"
|
||||
|
||||
struct VRDevice
|
||||
{
|
||||
int id = -1;
|
||||
vr::TrackedDeviceClass deviceClass;
|
||||
std::string model = "";
|
||||
std::string serial = "";
|
||||
std::string trackingSystem = "";
|
||||
vr::ETrackedControllerRole controllerRole = vr::TrackedControllerRole_Invalid;
|
||||
};
|
||||
|
||||
struct VRState
|
||||
{
|
||||
std::vector<std::string> trackingSystems;
|
||||
std::vector<VRDevice> devices;
|
||||
};
|
||||
|
||||
void TextWithWidth(const char *label, const char *text, float width);
|
||||
|
||||
VRState LoadVRState();
|
||||
void BuildSystemSelection(const VRState &state);
|
||||
void BuildDeviceSelections(const VRState &state);
|
||||
void BuildProfileEditor();
|
||||
|
||||
void BuildMainWindow(bool runningInOverlay)
|
||||
{
|
||||
ImGuiWindowFlags windowFlags =
|
||||
ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(io.DisplaySize, ImGuiSetCond_Always);
|
||||
|
||||
if (!ImGui::Begin("MainWindow", nullptr, windowFlags))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
|
||||
auto state = LoadVRState();
|
||||
BuildSystemSelection(state);
|
||||
BuildDeviceSelections(state);
|
||||
|
||||
ImGui::Text("");
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
float width = ImGui::GetWindowContentRegionWidth(), scale = 1.0f;
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
width -= style.FramePadding.x * 4.0f;
|
||||
scale = 1.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Start Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
ImGui::OpenPopup("Calibration Progress");
|
||||
StartCalibration();
|
||||
}
|
||||
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Edit Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.state = CalibrationState::Editing;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Clear Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.calibratedRotation = Eigen::Vector3d();
|
||||
CalCtx.calibratedTranslation = Eigen::Vector3d();
|
||||
CalCtx.validProfile = false;
|
||||
}
|
||||
}
|
||||
|
||||
width = ImGui::GetWindowContentRegionWidth();
|
||||
scale = 1.0f;
|
||||
if (CalCtx.chaperone.valid)
|
||||
{
|
||||
width -= style.FramePadding.x * 2.0f;
|
||||
scale = 0.5;
|
||||
}
|
||||
|
||||
ImGui::Text("");
|
||||
if (ImGui::Button("Copy Chaperone Bounds to profile", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
LoadChaperoneBounds();
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
|
||||
if (CalCtx.chaperone.valid)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Paste Chaperone Bounds", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
ApplyChaperoneBounds();
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox(" Paste Chaperone Bounds automatically when geometry resets", &CalCtx.chaperone.autoApply))
|
||||
{
|
||||
SaveProfile(CalCtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (CalCtx.state == CalibrationState::Editing)
|
||||
{
|
||||
BuildProfileEditor();
|
||||
|
||||
if (ImGui::Button("Save Profile", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
SaveProfile(CalCtx);
|
||||
CalCtx.state = CalibrationState::None;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Button("Calibration in progress...", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2));
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(20.0f, 20.0f), ImGuiSetCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(io.DisplaySize.x - 40.0f, io.DisplaySize.y - 40.0f), ImGuiSetCond_Always);
|
||||
if (ImGui::BeginPopupModal("Calibration Progress", nullptr, windowFlags))
|
||||
{
|
||||
ImGui::TextWrapped(CalCtx.messages.c_str());
|
||||
|
||||
if (CalCtx.state == CalibrationState::None)
|
||||
{
|
||||
ImGui::Text("");
|
||||
if (ImGui::Button("Close", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeight() * 2)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(10.0f, ImGui::GetWindowHeight() - ImGui::GetItemsLineHeightWithSpacing()));
|
||||
ImGui::BeginChild("bottom line", ImVec2(ImGui::GetWindowWidth() - 20.0f, ImGui::GetItemsLineHeightWithSpacing() * 2), false);
|
||||
ImGui::Text("OpenVR Space Calibrator v" VERSION_STRING " - by tach/pushrax");
|
||||
if (runningInOverlay)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("- close VR overlay to use mouse");
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void BuildSystemSelection(const VRState &state)
|
||||
{
|
||||
if (state.trackingSystems.empty())
|
||||
{
|
||||
ImGui::Text("No tracked devices are present");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
float paneWidth = ImGui::GetWindowContentRegionWidth() / 2 - style.FramePadding.x;
|
||||
|
||||
TextWithWidth("ReferenceSystemLabel", "Reference Space", paneWidth);
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("TargetSystemLabel", "Target Space", paneWidth);
|
||||
|
||||
int currentReferenceSystem = -1;
|
||||
int currentTargetSystem = -1;
|
||||
int firstReferenceSystemNotTargetSystem = -1;
|
||||
|
||||
std::vector<const char *> referenceSystems;
|
||||
for (auto &str : state.trackingSystems)
|
||||
{
|
||||
if (str == CalCtx.referenceTrackingSystem)
|
||||
{
|
||||
currentReferenceSystem = (int) referenceSystems.size();
|
||||
}
|
||||
else if (firstReferenceSystemNotTargetSystem == -1 && str != CalCtx.targetTrackingSystem)
|
||||
{
|
||||
firstReferenceSystemNotTargetSystem = (int) referenceSystems.size();
|
||||
}
|
||||
referenceSystems.push_back(str.c_str());
|
||||
}
|
||||
|
||||
if (currentReferenceSystem == -1 && CalCtx.referenceTrackingSystem == "")
|
||||
{
|
||||
currentReferenceSystem = firstReferenceSystemNotTargetSystem;
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(paneWidth);
|
||||
ImGui::Combo("##ReferenceTrackingSystem", ¤tReferenceSystem, &referenceSystems[0], (int) referenceSystems.size());
|
||||
|
||||
if (currentReferenceSystem != -1 && currentReferenceSystem < (int) referenceSystems.size())
|
||||
{
|
||||
CalCtx.referenceTrackingSystem = std::string(referenceSystems[currentReferenceSystem]);
|
||||
if (CalCtx.referenceTrackingSystem == CalCtx.targetTrackingSystem)
|
||||
CalCtx.targetTrackingSystem = "";
|
||||
}
|
||||
|
||||
if (CalCtx.targetTrackingSystem == "")
|
||||
currentTargetSystem = 0;
|
||||
|
||||
std::vector<const char *> targetSystems;
|
||||
for (auto &str : state.trackingSystems)
|
||||
{
|
||||
if (str != CalCtx.referenceTrackingSystem)
|
||||
{
|
||||
if (str != "" && str == CalCtx.targetTrackingSystem)
|
||||
currentTargetSystem = (int) targetSystems.size();
|
||||
targetSystems.push_back(str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(paneWidth);
|
||||
ImGui::Combo("##TargetTrackingSystem", ¤tTargetSystem, &targetSystems[0], (int) targetSystems.size());
|
||||
|
||||
if (currentTargetSystem != -1 && currentTargetSystem < targetSystems.size())
|
||||
{
|
||||
CalCtx.targetTrackingSystem = std::string(targetSystems[currentTargetSystem]);
|
||||
}
|
||||
}
|
||||
|
||||
void AppendSeparated(std::string &buffer, const std::string &suffix)
|
||||
{
|
||||
if (!buffer.empty())
|
||||
buffer += " | ";
|
||||
buffer += suffix;
|
||||
}
|
||||
|
||||
std::string LabelString(const VRDevice &device)
|
||||
{
|
||||
std::string label;
|
||||
|
||||
/*if (device.controllerRole == vr::TrackedControllerRole_LeftHand)
|
||||
label = "Left Controller";
|
||||
else if (device.controllerRole == vr::TrackedControllerRole_RightHand)
|
||||
label = "Right Controller";
|
||||
else if (device.deviceClass == vr::TrackedDeviceClass_Controller)
|
||||
label = "Controller";
|
||||
else if (device.deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
label = "HMD";
|
||||
else if (device.deviceClass == vr::TrackedDeviceClass_GenericTracker)
|
||||
label = "Tracker";*/
|
||||
|
||||
AppendSeparated(label, device.model);
|
||||
AppendSeparated(label, device.serial);
|
||||
return label;
|
||||
}
|
||||
|
||||
void BuildDeviceSelection(const VRState &state, int &selected, const std::string &system)
|
||||
{
|
||||
ImGui::TextColored(ImColor(0.5f, 0.5f, 0.5f), "Devices from: %s", system.c_str());
|
||||
|
||||
if (selected != -1)
|
||||
{
|
||||
bool matched = false;
|
||||
for (auto &device : state.devices)
|
||||
{
|
||||
if (device.trackingSystem != system)
|
||||
continue;
|
||||
|
||||
if (selected == device.id)
|
||||
{
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched)
|
||||
{
|
||||
// Device is no longer present.
|
||||
selected = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected == -1)
|
||||
{
|
||||
for (auto &device : state.devices)
|
||||
{
|
||||
if (device.trackingSystem != system)
|
||||
continue;
|
||||
|
||||
if (device.controllerRole == vr::TrackedControllerRole_LeftHand)
|
||||
{
|
||||
selected = device.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &device : state.devices)
|
||||
{
|
||||
if (device.trackingSystem != system)
|
||||
continue;
|
||||
|
||||
if (selected == -1)
|
||||
selected = device.id;
|
||||
|
||||
auto label = LabelString(device);
|
||||
if (ImGui::Selectable(label.c_str(), selected == device.id))
|
||||
selected = device.id;
|
||||
}
|
||||
}
|
||||
|
||||
void BuildDeviceSelections(const VRState &state)
|
||||
{
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
ImVec2 paneSize(ImGui::GetWindowContentRegionWidth() / 2 - style.FramePadding.x, ImGui::GetTextLineHeightWithSpacing() * 5 + style.ItemSpacing.y * 4);
|
||||
|
||||
ImGui::BeginChild("left device pane", paneSize, true);
|
||||
static int selectedRefDevice = -1;
|
||||
BuildDeviceSelection(state, selectedRefDevice, CalCtx.referenceTrackingSystem);
|
||||
CalCtx.referenceID = selectedRefDevice;
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginChild("right device pane", paneSize, true);
|
||||
static int selectedCalDevice = -1;
|
||||
BuildDeviceSelection(state, selectedCalDevice, CalCtx.targetTrackingSystem);
|
||||
CalCtx.targetID = selectedCalDevice;
|
||||
ImGui::EndChild();
|
||||
|
||||
if (ImGui::Button("Identify selected devices (blinks LED or vibrates)", ImVec2(ImGui::GetWindowContentRegionWidth(), ImGui::GetTextLineHeightWithSpacing() + 4.0f)))
|
||||
{
|
||||
for (unsigned i = 0; i < 100; ++i)
|
||||
{
|
||||
vr::VRSystem()->TriggerHapticPulse(CalCtx.targetID, 0, 2000);
|
||||
vr::VRSystem()->TriggerHapticPulse(CalCtx.referenceID, 0, 2000);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VRState LoadVRState()
|
||||
{
|
||||
VRState state;
|
||||
auto &trackingSystems = state.trackingSystems;
|
||||
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
vr::ETrackedPropertyError err = vr::TrackedProp_Success;
|
||||
auto deviceClass = vr::VRSystem()->GetTrackedDeviceClass(id);
|
||||
if (deviceClass == vr::TrackedDeviceClass_Invalid)
|
||||
continue;
|
||||
|
||||
if (deviceClass != vr::TrackedDeviceClass_TrackingReference)
|
||||
{
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_TrackingSystemName_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
|
||||
if (err == vr::TrackedProp_Success)
|
||||
{
|
||||
std::string system(buffer);
|
||||
auto existing = std::find(trackingSystems.begin(), trackingSystems.end(), system);
|
||||
if (existing != trackingSystems.end())
|
||||
{
|
||||
if (deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
{
|
||||
trackingSystems.erase(existing);
|
||||
trackingSystems.insert(trackingSystems.begin(), system);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trackingSystems.push_back(system);
|
||||
}
|
||||
|
||||
VRDevice device;
|
||||
device.id = id;
|
||||
device.deviceClass = deviceClass;
|
||||
device.trackingSystem = system;
|
||||
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_ModelNumber_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
device.model = std::string(buffer);
|
||||
|
||||
vr::VRSystem()->GetStringTrackedDeviceProperty(id, vr::Prop_SerialNumber_String, buffer, vr::k_unMaxPropertyStringSize, &err);
|
||||
device.serial = std::string(buffer);
|
||||
|
||||
device.controllerRole = (vr::ETrackedControllerRole) vr::VRSystem()->GetInt32TrackedDeviceProperty(id, vr::Prop_ControllerRoleHint_Int32, &err);
|
||||
state.devices.push_back(device);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("failed to get tracking system name for id %d\n", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
void BuildProfileEditor()
|
||||
{
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
float width = ImGui::GetWindowContentRegionWidth() / 3.0f - style.FramePadding.x;
|
||||
float widthF = width - style.FramePadding.x;
|
||||
|
||||
TextWithWidth("YawLabel", "Yaw", width);
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("PitchLabel", "Pitch", width);
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("RollLabel", "Roll", width);
|
||||
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Yaw", &CalCtx.calibratedRotation(1), 0.1, 1.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Pitch", &CalCtx.calibratedRotation(2), 0.1, 1.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Roll", &CalCtx.calibratedRotation(0), 0.1, 1.0, "%.8f");
|
||||
|
||||
TextWithWidth("XLabel", "X", width);
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("YLabel", "Y", width);
|
||||
ImGui::SameLine();
|
||||
TextWithWidth("ZLabel", "Z", width);
|
||||
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##X", &CalCtx.calibratedTranslation(0), 1.0, 10.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Y", &CalCtx.calibratedTranslation(1), 1.0, 10.0, "%.8f");
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(widthF);
|
||||
ImGui::InputDouble("##Z", &CalCtx.calibratedTranslation(2), 1.0, 10.0, "%.8f");
|
||||
}
|
||||
|
||||
void TextWithWidth(const char *label, const char *text, float width)
|
||||
{
|
||||
ImGui::BeginChild(label, ImVec2(width, ImGui::GetTextLineHeightWithSpacing()));
|
||||
ImGui::Text(text);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void BuildMainWindow(bool runningInOverlay);
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"source" : "builtin",
|
||||
"applications": [{
|
||||
"app_key": "pushrax.SpaceCalibrator",
|
||||
"launch_type": "binary",
|
||||
"binary_path_windows": "OpenVR-SpaceCalibrator.exe",
|
||||
"is_dashboard_overlay": true,
|
||||
|
||||
"strings": {
|
||||
"en_us": {
|
||||
"name": "Space Calibrator",
|
||||
"description": "OpenVR Space Calibrator Overlay"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 70 KiB |
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"alwaysActivate": true,
|
||||
"name" : "01spacecalibrator",
|
||||
"directory" : "",
|
||||
"resourceOnly" : false
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"jsonid" : "vrresources",
|
||||
"statusicons" : {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"driver_01spacecalibrator" : {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "Hooking.h"
|
||||
|
||||
std::map<std::string, IHook *> IHook::hooks;
|
||||
|
||||
bool IHook::Exists(const std::string &name)
|
||||
{
|
||||
return hooks.find(name) != hooks.end();
|
||||
}
|
||||
|
||||
void IHook::Register(IHook *hook)
|
||||
{
|
||||
hooks[hook->name] = hook;
|
||||
}
|
||||
|
||||
void IHook::Unregister(IHook *hook)
|
||||
{
|
||||
hooks.erase(hook->name);
|
||||
}
|
||||
|
||||
void IHook::DestroyAll()
|
||||
{
|
||||
for (auto &hook : hooks)
|
||||
{
|
||||
hook.second->Destroy();
|
||||
}
|
||||
hooks.clear();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "Logging.h"
|
||||
#include <MinHook.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class IHook
|
||||
{
|
||||
public:
|
||||
const std::string name;
|
||||
|
||||
IHook(const std::string &name) : name(name) { }
|
||||
virtual ~IHook() { }
|
||||
|
||||
virtual void Destroy() = 0;
|
||||
|
||||
static bool Exists(const std::string &name);
|
||||
static void Register(IHook *hook);
|
||||
static void Unregister(IHook *hook);
|
||||
static void DestroyAll();
|
||||
|
||||
private:
|
||||
static std::map<std::string, IHook *> hooks;
|
||||
};
|
||||
|
||||
template<class FuncType> class Hook : public IHook
|
||||
{
|
||||
public:
|
||||
FuncType originalFunc = nullptr;
|
||||
Hook(const std::string &name) : IHook(name) { }
|
||||
|
||||
bool CreateHookInObjectVTable(void *object, int vtableOffset, void *detourFunction)
|
||||
{
|
||||
// For virtual objects, VC++ adds a pointer to the vtable as the first member.
|
||||
// To access the vtable, we simply dereference the object.
|
||||
void **vtable = *((void ***)object);
|
||||
|
||||
// The vtable itself is an array of pointers to member functions,
|
||||
// in the order they were declared in.
|
||||
targetFunc = vtable[vtableOffset];
|
||||
|
||||
auto err = MH_CreateHook(targetFunc, detourFunction, (LPVOID *)&originalFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG("Failed to create hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
err = MH_EnableHook(targetFunc);
|
||||
if (err != MH_OK)
|
||||
{
|
||||
LOG("Failed to enable hook for %s, error: %s", name.c_str(), MH_StatusToString(err));
|
||||
MH_RemoveHook(targetFunc);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG("Enabled hook for %s", name.c_str());
|
||||
enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
MH_RemoveHook(targetFunc);
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled = false;
|
||||
void* targetFunc = nullptr;
|
||||
};
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "IPCServer.h"
|
||||
#include "Logging.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
|
||||
void IPCServer::HandleRequest(const protocol::Request &request, protocol::Response &response)
|
||||
{
|
||||
switch (request.type)
|
||||
{
|
||||
case protocol::RequestHandshake:
|
||||
response.type = protocol::ResponseHandshake;
|
||||
response.protocol.version = protocol::Version;
|
||||
break;
|
||||
|
||||
case protocol::RequestSetDeviceTransform:
|
||||
driver->SetDeviceTransform(request.setDeviceTransform);
|
||||
response.type = protocol::ResponseSuccess;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG("Invalid IPC request: %d", request.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IPCServer::~IPCServer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void IPCServer::Run()
|
||||
{
|
||||
mainThread = std::thread(RunThread, this);
|
||||
}
|
||||
|
||||
void IPCServer::Stop()
|
||||
{
|
||||
TRACE("IPCServer::Stop()");
|
||||
if (!running)
|
||||
return;
|
||||
|
||||
stop = true;
|
||||
SetEvent(connectEvent);
|
||||
mainThread.join();
|
||||
running = false;
|
||||
TRACE("IPCServer::Stop() finished");
|
||||
}
|
||||
|
||||
IPCServer::PipeInstance *IPCServer::CreatePipeInstance(HANDLE pipe)
|
||||
{
|
||||
auto pipeInst = new PipeInstance;
|
||||
pipeInst->pipe = pipe;
|
||||
pipeInst->server = this;
|
||||
pipes.insert(pipeInst);
|
||||
return pipeInst;
|
||||
}
|
||||
|
||||
void IPCServer::ClosePipeInstance(PipeInstance *pipeInst)
|
||||
{
|
||||
DisconnectNamedPipe(pipeInst->pipe);
|
||||
CloseHandle(pipeInst->pipe);
|
||||
pipes.erase(pipeInst);
|
||||
delete pipeInst;
|
||||
}
|
||||
|
||||
void IPCServer::RunThread(IPCServer *_this)
|
||||
{
|
||||
_this->running = true;
|
||||
LPTSTR pipeName = TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME);
|
||||
|
||||
HANDLE connectEvent = _this->connectEvent = CreateEvent(0, TRUE, TRUE, 0);
|
||||
if (!connectEvent)
|
||||
{
|
||||
LOG("CreateEvent failed in RunThread. Error: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
OVERLAPPED connectOverlap;
|
||||
connectOverlap.hEvent = connectEvent;
|
||||
|
||||
HANDLE nextPipe;
|
||||
BOOL connectPending = CreateAndConnectInstance(&connectOverlap, nextPipe);
|
||||
|
||||
while (!_this->stop)
|
||||
{
|
||||
DWORD wait = WaitForSingleObjectEx(connectEvent, INFINITE, TRUE);
|
||||
|
||||
if (_this->stop)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (wait == 0)
|
||||
{
|
||||
// When connectPending is false, the last call to CreateAndConnectInstance
|
||||
// picked up a connected client and triggered this event, so we can simply
|
||||
// create a new pipe instance for it. If true, the client was still pending
|
||||
// connection when CreateAndConnectInstance returned, so this event was triggered
|
||||
// internally and we need to flush out the result, or something like that.
|
||||
if (connectPending)
|
||||
{
|
||||
DWORD bytesConnect;
|
||||
BOOL success = GetOverlappedResult(nextPipe, &connectOverlap, &bytesConnect, FALSE);
|
||||
if (!success)
|
||||
{
|
||||
LOG("GetOverlappedResult failed in RunThread. Error: %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("IPC client connected");
|
||||
|
||||
auto pipeInst = _this->CreatePipeInstance(nextPipe);
|
||||
CompletedWriteCallback(0, sizeof protocol::Response, (LPOVERLAPPED) pipeInst);
|
||||
|
||||
connectPending = CreateAndConnectInstance(&connectOverlap, nextPipe);
|
||||
}
|
||||
else if (wait != WAIT_IO_COMPLETION)
|
||||
{
|
||||
printf("WaitForSingleObjectEx failed in RunThread. Error %d", GetLastError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pipeInst : _this->pipes)
|
||||
{
|
||||
_this->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
_this->pipes.clear();
|
||||
}
|
||||
|
||||
BOOL IPCServer::CreateAndConnectInstance(LPOVERLAPPED overlap, HANDLE &pipe)
|
||||
{
|
||||
pipe = CreateNamedPipe(
|
||||
TEXT(OPENVR_SPACECALIBRATOR_PIPE_NAME),
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES,
|
||||
sizeof protocol::Request,
|
||||
sizeof protocol::Response,
|
||||
1000,
|
||||
0
|
||||
);
|
||||
|
||||
if (pipe == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
LOG("CreateNamedPipe failed. Error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ConnectNamedPipe(pipe, overlap);
|
||||
|
||||
switch(GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
// Mark a pending connection by returning true, and when the connection
|
||||
// completes an event will trigger automatically.
|
||||
return TRUE;
|
||||
|
||||
case ERROR_PIPE_CONNECTED:
|
||||
// Signal the event loop that a client is connected.
|
||||
if (SetEvent(overlap->hEvent))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LOG("ConnectNamedPipe failed. Error: %d", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void IPCServer::CompletedReadCallback(DWORD err, DWORD bytesRead, LPOVERLAPPED overlap)
|
||||
{
|
||||
PipeInstance *pipeInst = (PipeInstance *) overlap;
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (err == 0 && bytesRead > 0)
|
||||
{
|
||||
pipeInst->server->HandleRequest(pipeInst->request, pipeInst->response);
|
||||
success = WriteFileEx(
|
||||
pipeInst->pipe,
|
||||
&pipeInst->response,
|
||||
sizeof protocol::Response,
|
||||
overlap,
|
||||
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteCallback
|
||||
);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
if (err == ERROR_BROKEN_PIPE)
|
||||
{
|
||||
LOG("IPC client disconnecting normally");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("IPC client disconnecting due to error (via CompletedReadCallback), error: %d, bytesRead: %d", err, bytesRead);
|
||||
}
|
||||
pipeInst->server->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
}
|
||||
|
||||
void IPCServer::CompletedWriteCallback(DWORD err, DWORD bytesWritten, LPOVERLAPPED overlap)
|
||||
{
|
||||
PipeInstance *pipeInst = (PipeInstance *) overlap;
|
||||
BOOL success = FALSE;
|
||||
|
||||
if (err == 0 && bytesWritten == sizeof protocol::Response)
|
||||
{
|
||||
success = ReadFileEx(
|
||||
pipeInst->pipe,
|
||||
&pipeInst->request,
|
||||
sizeof protocol::Request,
|
||||
overlap,
|
||||
(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadCallback
|
||||
);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
LOG("IPC client disconnecting due to error (via CompletedWriteCallback), error: %d, bytesWritten: %d", err, bytesWritten);
|
||||
pipeInst->server->ClosePipeInstance(pipeInst);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Protocol.h"
|
||||
|
||||
#include <thread>
|
||||
#include <set>
|
||||
#include <mutex>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
class ServerTrackedDeviceProvider;
|
||||
|
||||
class IPCServer
|
||||
{
|
||||
public:
|
||||
IPCServer(ServerTrackedDeviceProvider *driver) : driver(driver) { }
|
||||
~IPCServer();
|
||||
|
||||
void Run();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void HandleRequest(const protocol::Request &request, protocol::Response &response);
|
||||
|
||||
struct PipeInstance
|
||||
{
|
||||
OVERLAPPED overlap; // Used by the API
|
||||
HANDLE pipe;
|
||||
IPCServer *server;
|
||||
|
||||
protocol::Request request;
|
||||
protocol::Response response;
|
||||
};
|
||||
|
||||
PipeInstance *CreatePipeInstance(HANDLE pipe);
|
||||
void ClosePipeInstance(PipeInstance *pipeInst);
|
||||
|
||||
static void RunThread(IPCServer *_this);
|
||||
static BOOL CreateAndConnectInstance(LPOVERLAPPED overlap, HANDLE &pipe);
|
||||
static void WINAPI CompletedReadCallback(DWORD err, DWORD bytesRead, LPOVERLAPPED overlap);
|
||||
static void WINAPI CompletedWriteCallback(DWORD err, DWORD bytesWritten, LPOVERLAPPED overlap);
|
||||
|
||||
std::thread mainThread;
|
||||
|
||||
bool running = false;
|
||||
bool stop = false;
|
||||
|
||||
std::set<PipeInstance *> pipes;
|
||||
HANDLE connectEvent;
|
||||
|
||||
ServerTrackedDeviceProvider *driver;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "Logging.h"
|
||||
#include "Hooking.h"
|
||||
#include "InterfaceHookInjector.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
|
||||
static ServerTrackedDeviceProvider *Driver = nullptr;
|
||||
|
||||
static Hook<void*(*)(vr::IVRDriverContext *, const char *, vr::EVRInitError *)>
|
||||
GetGenericInterfaceHook("IVRDriverContext::GetGenericInterface");
|
||||
|
||||
static Hook<void(*)(vr::IVRServerDriverHost *, uint32_t, const vr::DriverPose_t &, uint32_t)>
|
||||
TrackedDevicePoseUpdatedHook("IVRServerDriverHost005::TrackedDevicePoseUpdated");
|
||||
|
||||
static void DetourTrackedDevicePoseUpdated(vr::IVRServerDriverHost *_this, uint32_t unWhichDevice, const vr::DriverPose_t &newPose, uint32_t unPoseStructSize)
|
||||
{
|
||||
//TRACE("ServerTrackedDeviceProvider::DetourTrackedDevicePoseUpdated(%d)", unWhichDevice);
|
||||
auto pose = newPose;
|
||||
if (Driver->HandleDevicePoseUpdated(unWhichDevice, pose))
|
||||
{
|
||||
TrackedDevicePoseUpdatedHook.originalFunc(_this, unWhichDevice, pose, unPoseStructSize);
|
||||
}
|
||||
}
|
||||
|
||||
static void *DetourGetGenericInterface(vr::IVRDriverContext *_this, const char *pchInterfaceVersion, vr::EVRInitError *peError)
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::DetourGetGenericInterface(%s)", pchInterfaceVersion);
|
||||
auto originalInterface = GetGenericInterfaceHook.originalFunc(_this, pchInterfaceVersion, peError);
|
||||
|
||||
std::string iface(pchInterfaceVersion);
|
||||
if (iface == "IVRServerDriverHost_005")
|
||||
{
|
||||
if (!IHook::Exists(TrackedDevicePoseUpdatedHook.name))
|
||||
{
|
||||
TrackedDevicePoseUpdatedHook.CreateHookInObjectVTable(originalInterface, 1, &DetourTrackedDevicePoseUpdated);
|
||||
IHook::Register(&TrackedDevicePoseUpdatedHook);
|
||||
}
|
||||
}
|
||||
|
||||
return originalInterface;
|
||||
}
|
||||
|
||||
void InjectHooks(ServerTrackedDeviceProvider *driver, vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
Driver = driver;
|
||||
|
||||
auto err = MH_Initialize();
|
||||
if (err == MH_OK)
|
||||
{
|
||||
GetGenericInterfaceHook.CreateHookInObjectVTable(pDriverContext, 0, &DetourGetGenericInterface);
|
||||
IHook::Register(&GetGenericInterfaceHook);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("MH_Initialize error: %s", MH_StatusToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
void DisableHooks()
|
||||
{
|
||||
IHook::DestroyAll();
|
||||
MH_Uninitialize();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class ServerTrackedDeviceProvider;
|
||||
|
||||
static void DetourTrackedDevicePoseUpdated(vr::IVRServerDriverHost * _this, uint32_t unWhichDevice, const vr::DriverPose_t & newPose, uint32_t unPoseStructSize);
|
||||
|
||||
void InjectHooks(ServerTrackedDeviceProvider *driver, vr::IVRDriverContext *pDriverContext);
|
||||
void DisableHooks();
|
||||
@@ -0,0 +1,28 @@
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#include "Logging.h"
|
||||
#include <chrono>
|
||||
|
||||
FILE *LogFile;
|
||||
|
||||
void OpenLogFile()
|
||||
{
|
||||
LogFile = fopen("space_calibrator_driver.log", "a");
|
||||
if (LogFile == nullptr)
|
||||
{
|
||||
LogFile = stderr;
|
||||
}
|
||||
}
|
||||
|
||||
tm TimeForLog()
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto nowTime = std::chrono::system_clock::to_time_t(now);
|
||||
tm value;
|
||||
auto tm = localtime_s(&value, &nowTime);
|
||||
return value;
|
||||
}
|
||||
|
||||
void LogFlush()
|
||||
{
|
||||
fflush(LogFile);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
extern FILE *LogFile;
|
||||
|
||||
void OpenLogFile();
|
||||
tm TimeForLog();
|
||||
void LogFlush();
|
||||
|
||||
#ifndef LOG
|
||||
#define LOG(fmt, ...) do { \
|
||||
tm logNow = TimeForLog(); \
|
||||
fprintf(LogFile, "[%02d:%02d:%02d] " fmt "\n", logNow.tm_hour, logNow.tm_min, logNow.tm_sec, __VA_ARGS__); \
|
||||
LogFlush(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define TRACE(...) {}
|
||||
|
||||
#ifndef TRACE
|
||||
#define TRACE LOG
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "OpenVR-SpaceCalibratorDriver.h"
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
#include "VRWatchdogProvider.h"
|
||||
#include "Logging.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <openvr_driver.h>
|
||||
|
||||
OPENVRSPACECALIBRATORDRIVER_API void *HmdDriverFactory(const char *pInterfaceName, int *pReturnCode)
|
||||
{
|
||||
TRACE("HmdDriverFactory(%s)", pInterfaceName);
|
||||
|
||||
static ServerTrackedDeviceProvider server;
|
||||
static VRWatchdogProvider watchdog;
|
||||
|
||||
if (std::strcmp(vr::IServerTrackedDeviceProvider_Version, pInterfaceName) == 0)
|
||||
{
|
||||
return &server;
|
||||
}
|
||||
else if (std::strcmp(vr::IVRWatchdogProvider_Version, pInterfaceName) == 0)
|
||||
{
|
||||
return &watchdog;
|
||||
}
|
||||
|
||||
if (pReturnCode)
|
||||
{
|
||||
*pReturnCode = vr::VRInitError_Init_InterfaceNotFound;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef OPENVRSPACECALIBRATORDRIVER_EXPORTS
|
||||
#define OPENVRSPACECALIBRATORDRIVER_API extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define OPENVRSPACECALIBRATORDRIVER_API extern "C" __declspec(dllimport)
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A61324AD-CE32-46D1-A95E-7E28A6D8CCA7}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>OpenVRSpaceCalibratorDriver</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>driver_01spacecalibrator</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>driver_01spacecalibrator</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;OPENVRSPACECALIBRATORDRIVER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\MinHook\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\MinHook\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libMinHook-x64-v140-mdd.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;OPENVRSPACECALIBRATORDRIVER_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\lib\openvr;..\lib\MinHook\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>..\lib\MinHook\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>libMinHook-x64-v140-md.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Protocol.h" />
|
||||
<ClInclude Include="Hooking.h" />
|
||||
<ClInclude Include="InterfaceHookInjector.h" />
|
||||
<ClInclude Include="IPCServer.h" />
|
||||
<ClInclude Include="Logging.h" />
|
||||
<ClInclude Include="OpenVR-SpaceCalibratorDriver.h" />
|
||||
<ClInclude Include="ServerTrackedDeviceProvider.h" />
|
||||
<ClInclude Include="VRWatchdogProvider.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Hooking.cpp" />
|
||||
<ClCompile Include="InterfaceHookInjector.cpp" />
|
||||
<ClCompile Include="IPCServer.cpp" />
|
||||
<ClCompile Include="Logging.cpp" />
|
||||
<ClCompile Include="OpenVR-SpaceCalibratorDriver.cpp" />
|
||||
<ClCompile Include="ServerTrackedDeviceProvider.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="OpenVR-SpaceCalibratorDriver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Logging.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ServerTrackedDeviceProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VRWatchdogProvider.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IPCServer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Protocol.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Hooking.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InterfaceHookInjector.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="OpenVR-SpaceCalibratorDriver.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Logging.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ServerTrackedDeviceProvider.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPCServer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Hooking.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InterfaceHookInjector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "ServerTrackedDeviceProvider.h"
|
||||
#include "Logging.h"
|
||||
#include "InterfaceHookInjector.h"
|
||||
|
||||
vr::EVRInitError ServerTrackedDeviceProvider::Init(vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::Init()");
|
||||
VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext);
|
||||
|
||||
memset(transforms, 0, vr::k_unMaxTrackedDeviceCount * sizeof DeviceTransform);
|
||||
|
||||
InjectHooks(this, pDriverContext);
|
||||
server.Run();
|
||||
|
||||
return vr::VRInitError_None;
|
||||
}
|
||||
|
||||
void ServerTrackedDeviceProvider::Cleanup()
|
||||
{
|
||||
TRACE("ServerTrackedDeviceProvider::Cleanup()");
|
||||
server.Stop();
|
||||
DisableHooks();
|
||||
VR_CLEANUP_SERVER_DRIVER_CONTEXT();
|
||||
}
|
||||
|
||||
inline vr::HmdQuaternion_t operator*(const vr::HmdQuaternion_t &lhs, const vr::HmdQuaternion_t &rhs) {
|
||||
return {
|
||||
(lhs.w * rhs.w) - (lhs.x * rhs.x) - (lhs.y * rhs.y) - (lhs.z * rhs.z),
|
||||
(lhs.w * rhs.x) + (lhs.x * rhs.w) + (lhs.y * rhs.z) - (lhs.z * rhs.y),
|
||||
(lhs.w * rhs.y) + (lhs.y * rhs.w) + (lhs.z * rhs.x) - (lhs.x * rhs.z),
|
||||
(lhs.w * rhs.z) + (lhs.z * rhs.w) + (lhs.x * rhs.y) - (lhs.y * rhs.x)
|
||||
};
|
||||
}
|
||||
|
||||
inline vr::HmdVector3d_t quaternionRotateVector(const vr::HmdQuaternion_t& quat, const double(&vector)[3]) {
|
||||
vr::HmdQuaternion_t vectorQuat = { 0.0, vector[0], vector[1] , vector[2] };
|
||||
vr::HmdQuaternion_t conjugate = { quat.w, -quat.x, -quat.y, -quat.z };
|
||||
auto rotatedVectorQuat = quat * vectorQuat * conjugate;
|
||||
return { rotatedVectorQuat.x, rotatedVectorQuat.y, rotatedVectorQuat.z };
|
||||
}
|
||||
|
||||
void ServerTrackedDeviceProvider::SetDeviceTransform(const protocol::SetDeviceTransform &newTransform)
|
||||
{
|
||||
auto &tf = transforms[newTransform.openVRID];
|
||||
tf.enabled = newTransform.enabled;
|
||||
|
||||
if (newTransform.updateTranslation)
|
||||
tf.translation = newTransform.translation;
|
||||
|
||||
if (newTransform.updateRotation)
|
||||
tf.rotation = newTransform.rotation;
|
||||
}
|
||||
|
||||
bool ServerTrackedDeviceProvider::HandleDevicePoseUpdated(uint32_t openVRID, vr::DriverPose_t &pose)
|
||||
{
|
||||
auto &tf = transforms[openVRID];
|
||||
if (tf.enabled)
|
||||
{
|
||||
pose.qWorldFromDriverRotation = tf.rotation * pose.qWorldFromDriverRotation;
|
||||
|
||||
vr::HmdVector3d_t rotatedTranslation = quaternionRotateVector(tf.rotation, pose.vecWorldFromDriverTranslation);
|
||||
pose.vecWorldFromDriverTranslation[0] = rotatedTranslation.v[0] + tf.translation.v[0];
|
||||
pose.vecWorldFromDriverTranslation[1] = rotatedTranslation.v[1] + tf.translation.v[1];
|
||||
pose.vecWorldFromDriverTranslation[2] = rotatedTranslation.v[2] + tf.translation.v[2];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "IPCServer.h"
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class ServerTrackedDeviceProvider : public vr::IServerTrackedDeviceProvider
|
||||
{
|
||||
public:
|
||||
////// Start vr::IServerTrackedDeviceProvider functions
|
||||
|
||||
/** initializes the driver. This will be called before any other methods are called. */
|
||||
virtual vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext) override;
|
||||
|
||||
/** cleans up the driver right before it is unloaded */
|
||||
virtual void Cleanup() override;
|
||||
|
||||
/** Returns the version of the ITrackedDeviceServerDriver interface used by this driver */
|
||||
virtual const char * const *GetInterfaceVersions() { return vr::k_InterfaceVersions; }
|
||||
|
||||
/** Allows the driver do to some work in the main loop of the server. */
|
||||
virtual void RunFrame() { }
|
||||
|
||||
/** Returns true if the driver wants to block Standby mode. */
|
||||
virtual bool ShouldBlockStandbyMode() { return false; }
|
||||
|
||||
/** Called when the system is entering Standby mode. The driver should switch itself into whatever sort of low-power
|
||||
* state it has. */
|
||||
virtual void EnterStandby() { }
|
||||
|
||||
/** Called when the system is leaving Standby mode. The driver should switch itself back to
|
||||
full operation. */
|
||||
virtual void LeaveStandby() { }
|
||||
|
||||
////// End vr::IServerTrackedDeviceProvider functions
|
||||
|
||||
ServerTrackedDeviceProvider() : server(this) { }
|
||||
void SetDeviceTransform(const protocol::SetDeviceTransform &newTransform);
|
||||
bool HandleDevicePoseUpdated(uint32_t openVRID, vr::DriverPose_t &pose);
|
||||
|
||||
private:
|
||||
IPCServer server;
|
||||
|
||||
struct DeviceTransform
|
||||
{
|
||||
bool enabled = false;
|
||||
vr::HmdVector3d_t translation;
|
||||
vr::HmdQuaternion_t rotation;
|
||||
};
|
||||
|
||||
DeviceTransform transforms[vr::k_unMaxTrackedDeviceCount];
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <openvr_driver.h>
|
||||
|
||||
class VRWatchdogProvider : public vr::IVRWatchdogProvider
|
||||
{
|
||||
/** initializes the driver in watchdog mode. */
|
||||
virtual vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext)
|
||||
{
|
||||
VR_INIT_WATCHDOG_DRIVER_CONTEXT(pDriverContext);
|
||||
return vr::VRInitError_None;
|
||||
}
|
||||
|
||||
/** cleans up the driver right before it is unloaded */
|
||||
virtual void Cleanup()
|
||||
{
|
||||
VR_CLEANUP_WATCHDOG_DRIVER_CONTEXT()
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "Logging.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <cstdio>
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
OpenLogFile();
|
||||
LOG("OpenVR-SpaceCalibratorDriver loaded");
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
LOG("OpenVR-SpaceCalibratorDriver unloaded");
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef _OPENVR_API
|
||||
#include <openvr_driver.h>
|
||||
#endif
|
||||
|
||||
#define OPENVR_SPACECALIBRATOR_PIPE_NAME "\\\\.\\pipe\\OpenVRSpaceCalibratorDriver"
|
||||
|
||||
namespace protocol
|
||||
{
|
||||
const uint32_t Version = 1;
|
||||
|
||||
enum RequestType
|
||||
{
|
||||
RequestInvalid,
|
||||
RequestHandshake,
|
||||
RequestSetDeviceTransform,
|
||||
};
|
||||
|
||||
enum ResponseType
|
||||
{
|
||||
ResponseInvalid,
|
||||
ResponseHandshake,
|
||||
ResponseSuccess,
|
||||
};
|
||||
|
||||
struct Protocol
|
||||
{
|
||||
uint32_t version = Version;
|
||||
};
|
||||
|
||||
struct SetDeviceTransform
|
||||
{
|
||||
uint32_t openVRID;
|
||||
bool enabled;
|
||||
bool updateTranslation;
|
||||
bool updateRotation;
|
||||
vr::HmdVector3d_t translation;
|
||||
vr::HmdQuaternion_t rotation;
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(false), updateRotation(false) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdVector3d_t translation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(true), updateRotation(false), translation(translation) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdQuaternion_t rotation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(false), updateRotation(true), rotation(rotation) { }
|
||||
|
||||
SetDeviceTransform(uint32_t id, bool enabled, vr::HmdVector3d_t translation, vr::HmdQuaternion_t rotation) :
|
||||
openVRID(id), enabled(enabled), updateTranslation(true), updateRotation(true), translation(translation), rotation(rotation) { }
|
||||
};
|
||||
|
||||
struct Request
|
||||
{
|
||||
RequestType type;
|
||||
|
||||
union {
|
||||
SetDeviceTransform setDeviceTransform;
|
||||
};
|
||||
|
||||
Request() : type(RequestInvalid) { }
|
||||
Request(RequestType type) : type(type) { }
|
||||
};
|
||||
|
||||
struct Response
|
||||
{
|
||||
ResponseType type;
|
||||
|
||||
union {
|
||||
Protocol protocol;
|
||||
};
|
||||
|
||||
Response() : type(ResponseInvalid) { }
|
||||
Response(ResponseType type) : type(type) { }
|
||||
};
|
||||
}
|
||||
@@ -10,7 +10,6 @@ This is **beta software** and may not work for you. A quick video walkthrough of
|
||||
|
||||
If you don't already run a setup with multiple device types, see [Setting up SteamVR](#setting-up-steamvr).
|
||||
|
||||
0. Install [OpenVR-InputEmulator](https://github.com/matzman666/OpenVR-InputEmulator).
|
||||
1. Download and unzip the [latest release](https://github.com/pushrax/OpenVR-SpaceCalibrator/releases) of OpenVR-SpaceCalibrator.
|
||||
2. Run SteamVR, and turn on your Touch controllers and only one Vive device to use for calibration.
|
||||
3. Run OpenVR-SpaceCalibrator.
|
||||
@@ -19,7 +18,8 @@ If you don't already run a setup with multiple device types, see [Setting up Ste
|
||||
6. Wave your left hand around, like you're calibrating the compass on your phone. You want to get as many orientations as possible.
|
||||
7. Done! A profile will be saved automatically. You can turn on the rest of your Vive devices now.
|
||||
|
||||
Next time you run SteamVR and OpenVR-InputEmulator it will load the calibration automatically and apply it to any Vive devices you turn on.
|
||||
Next time you run SteamVR, open OpenVR-SpaceCalibrator and it will load the calibration automatically and apply it devices you turn on.
|
||||
|
||||
|
||||
### Setting up SteamVR
|
||||
|
||||
@@ -35,15 +35,10 @@ unless you truly want to be able to run without any kind of HMD.
|
||||
Sometimes when SteamVR updates this file seems to get wiped, if your setup stops working you might
|
||||
have to edit the config again.
|
||||
|
||||
### Manually editing the calibration
|
||||
|
||||
If you'd like to make a manual change to the calibration, the values are in `openvr_space_calibration.txt` in the same folder as the exe.
|
||||
The first 3 numbers are the rotation (yaw, pitch, roll) in degrees, and the next 3 numbers are the translation (x, y, z) in centimeters.
|
||||
|
||||
### Compiling your own build
|
||||
|
||||
1. Install boost 1.63 to `lib/boost_1_63_0` (required for IPC to OpenVR-InputEmulator). https://sourceforge.net/projects/boost/files/boost-binaries/1.63.0/
|
||||
2. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
|
||||
1. Open `OpenVR-SpaceCalibrator.sln` in Visual Studio 2015 and build.
|
||||
|
||||
|
||||
## The math
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
;--------------------------------
|
||||
;Include Modern UI
|
||||
|
||||
!include "MUI2.nsh"
|
||||
|
||||
;--------------------------------
|
||||
;General
|
||||
|
||||
!define OVERLAY_BASEDIR "..\client_overlay\bin\win64"
|
||||
!define DRIVER_RESDIR "..\OpenVR-SpaceCalibratorDriver\01spacecalibrator"
|
||||
|
||||
Name "OpenVR-SpaceCalibrator"
|
||||
OutFile "OpenVR-SpaceCalibrator.exe"
|
||||
InstallDir "$PROGRAMFILES64\OpenVR-SpaceCalibrator"
|
||||
InstallDirRegKey HKLM "Software\OpenVR-SpaceCalibrator\Main" ""
|
||||
RequestExecutionLevel admin
|
||||
ShowInstDetails show
|
||||
|
||||
;--------------------------------
|
||||
;Variables
|
||||
|
||||
VAR upgradeInstallation
|
||||
|
||||
;--------------------------------
|
||||
;Interface Settings
|
||||
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
;--------------------------------
|
||||
;Pages
|
||||
|
||||
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE dirPre
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_UNPAGE_CONFIRM
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
;--------------------------------
|
||||
;Languages
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
;--------------------------------
|
||||
;Macros
|
||||
|
||||
;--------------------------------
|
||||
;Functions
|
||||
|
||||
Function dirPre
|
||||
StrCmp $upgradeInstallation "true" 0 +2
|
||||
Abort
|
||||
FunctionEnd
|
||||
|
||||
Function .onInit
|
||||
StrCpy $upgradeInstallation "false"
|
||||
|
||||
ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "UninstallString"
|
||||
StrCmp $R0 "" done
|
||||
|
||||
|
||||
; If SteamVR is already running, display a warning message and exit
|
||||
FindWindow $0 "Qt5QWindowIcon" "SteamVR Status"
|
||||
StrCmp $0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION \
|
||||
"SteamVR is still running. Cannot install this software.$\nPlease close SteamVR and try again."
|
||||
Abort
|
||||
|
||||
|
||||
MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \
|
||||
"OpenVR-SpaceCalibrator is already installed. $\n$\nClick `OK` to upgrade the \
|
||||
existing installation or `Cancel` to cancel this upgrade." \
|
||||
IDOK upgrade
|
||||
Abort
|
||||
|
||||
upgrade:
|
||||
StrCpy $upgradeInstallation "true"
|
||||
done:
|
||||
FunctionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Installer Sections
|
||||
|
||||
Section "Install" SecInstall
|
||||
|
||||
StrCmp $upgradeInstallation "true" 0 noupgrade
|
||||
DetailPrint "Uninstall previous version..."
|
||||
ExecWait '"$INSTDIR\Uninstall.exe" /S _?=$INSTDIR'
|
||||
Delete $INSTDIR\Uninstall.exe
|
||||
Goto afterupgrade
|
||||
|
||||
noupgrade:
|
||||
|
||||
afterupgrade:
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
|
||||
File "..\LICENSE"
|
||||
File "..\x64\Release\OpenVR-SpaceCalibrator.exe"
|
||||
File "..\x64\Release\openvr_api.dll"
|
||||
File "..\OpenVR-SpaceCalibrator\manifest.vrmanifest"
|
||||
File "..\OpenVR-SpaceCalibrator\icon.png"
|
||||
|
||||
ExecWait '"$INSTDIR\vcredist_x64.exe" /install /quiet'
|
||||
|
||||
Var /GLOBAL vrRuntimePath
|
||||
nsExec::ExecToStack '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -openvrpath'
|
||||
Pop $0
|
||||
Pop $vrRuntimePath
|
||||
DetailPrint "VR runtime path: $vrRuntimePath"
|
||||
|
||||
; Old beta driver
|
||||
StrCmp $upgradeInstallation "true" 0 nocleanupbeta
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\driver.vrdrivermanifest"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\resources\driver.vrresources"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\resources\settings\default.vrsettings"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\driver_000spacecalibrator.dll"
|
||||
Delete "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\space_calibrator_driver.log"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\resources\settings"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\resources\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\bin\win64\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\bin\"
|
||||
RMdir "$vrRuntimePath\drivers\000spacecalibrator\"
|
||||
nocleanupbeta:
|
||||
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator"
|
||||
File "${DRIVER_RESDIR}\driver.vrdrivermanifest"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\resources"
|
||||
File "${DRIVER_RESDIR}\resources\driver.vrresources"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\resources\settings"
|
||||
File "${DRIVER_RESDIR}\resources\settings\default.vrsettings"
|
||||
SetOutPath "$vrRuntimePath\drivers\01spacecalibrator\bin\win64"
|
||||
File "..\x64\Release\driver_01spacecalibrator.dll"
|
||||
|
||||
WriteRegStr HKLM "Software\OpenVR-SpaceCalibrator\Main" "" $INSTDIR
|
||||
WriteRegStr HKLM "Software\OpenVR-SpaceCalibrator\Driver" "" $vrRuntimePath
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "DisplayName" "OpenVR-SpaceCalibrator"
|
||||
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator" "UninstallString" "$\"$INSTDIR\Uninstall.exe$\""
|
||||
|
||||
CreateShortCut "$SMPROGRAMS\OpenVR-SpaceCalibrator.lnk" "$INSTDIR\OpenVR-SpaceCalibrator.exe"
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -installmanifest'
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -activatemultipledrivers'
|
||||
|
||||
SectionEnd
|
||||
|
||||
;--------------------------------
|
||||
;Uninstaller Section
|
||||
|
||||
Section "Uninstall"
|
||||
; If SteamVR is already running, display a warning message and exit
|
||||
FindWindow $0 "Qt5QWindowIcon" "SteamVR Status"
|
||||
StrCmp $0 0 +3
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION \
|
||||
"SteamVR is still running. Cannot uninstall this software.$\nPlease close SteamVR and try again."
|
||||
Abort
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
nsExec::ExecToLog '"$INSTDIR\OpenVR-SpaceCalibrator.exe" -removemanifest'
|
||||
|
||||
Var /GLOBAL vrRuntimePath2
|
||||
ReadRegStr $vrRuntimePath2 HKLM "Software\OpenVR-SpaceCalibrator\Driver" ""
|
||||
DetailPrint "VR runtime path: $vrRuntimePath2"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\driver.vrdrivermanifest"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\resources\driver.vrresources"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\resources\settings\default.vrsettings"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\driver_01spacecalibrator.dll"
|
||||
Delete "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\space_calibrator_driver.log"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\resources\settings"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\resources\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\bin\win64\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\bin\"
|
||||
RMdir "$vrRuntimePath2\drivers\01spacecalibrator\"
|
||||
|
||||
Delete "$INSTDIR\LICENSE"
|
||||
Delete "$INSTDIR\OpenVR-SpaceCalibrator.exe"
|
||||
Delete "$INSTDIR\openvr_api.dll"
|
||||
Delete "$INSTDIR\manifest.vrmanifest"
|
||||
Delete "$INSTDIR\icon.png"
|
||||
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator\Main"
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator\Driver"
|
||||
DeleteRegKey HKLM "Software\OpenVR-SpaceCalibrator"
|
||||
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenVRSpaceCalibrator"
|
||||
|
||||
Delete "$SMPROGRAMS\OpenVR-SpaceCalibrator.lnk"
|
||||
SectionEnd
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
================================================================================
|
||||
Portions of this software are Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
================================================================================
|
||||
Hacker Disassembler Engine 32 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
Hacker Disassembler Engine 64 C
|
||||
Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a Hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a Hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszTarget [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char * WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,282 @@
|
||||
#ifndef __khrplatform_h_
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
** "Materials"), to deal in the Materials without restriction, including
|
||||
** without limitation the rights to use, copy, modify, merge, publish,
|
||||
** distribute, sublicense, and/or sell copies of the Materials, and to
|
||||
** permit persons to whom the Materials are furnished to do so, subject to
|
||||
** the following conditions:
|
||||
**
|
||||
** The above copyright notice and this permission notice shall be included
|
||||
** in all copies or substantial portions of the Materials.
|
||||
**
|
||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
|
||||
*/
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
* should be located on your system and for more details of its use:
|
||||
* http://www.khronos.org/registry/implementers_guide.pdf
|
||||
*
|
||||
* This file should be included as
|
||||
* #include <KHR/khrplatform.h>
|
||||
* by Khronos client API header files that use its types and defines.
|
||||
*
|
||||
* The types in khrplatform.h should only be used to define API-specific types.
|
||||
*
|
||||
* Types defined in khrplatform.h:
|
||||
* khronos_int8_t signed 8 bit
|
||||
* khronos_uint8_t unsigned 8 bit
|
||||
* khronos_int16_t signed 16 bit
|
||||
* khronos_uint16_t unsigned 16 bit
|
||||
* khronos_int32_t signed 32 bit
|
||||
* khronos_uint32_t unsigned 32 bit
|
||||
* khronos_int64_t signed 64 bit
|
||||
* khronos_uint64_t unsigned 64 bit
|
||||
* khronos_intptr_t signed same number of bits as a pointer
|
||||
* khronos_uintptr_t unsigned same number of bits as a pointer
|
||||
* khronos_ssize_t signed size
|
||||
* khronos_usize_t unsigned size
|
||||
* khronos_float_t signed 32 bit floating point
|
||||
* khronos_time_ns_t unsigned 64 bit time in nanoseconds
|
||||
* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
|
||||
* nanoseconds
|
||||
* khronos_stime_nanoseconds_t signed time interval in nanoseconds
|
||||
* khronos_boolean_enum_t enumerated boolean type. This should
|
||||
* only be used as a base type when a client API's boolean type is
|
||||
* an enum. Client APIs which use an integer or other type for
|
||||
* booleans cannot use this as the base type for their boolean.
|
||||
*
|
||||
* Tokens defined in khrplatform.h:
|
||||
*
|
||||
* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
|
||||
*
|
||||
* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
|
||||
* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
|
||||
*
|
||||
* Calling convention macros defined in this file:
|
||||
* KHRONOS_APICALL
|
||||
* KHRONOS_APIENTRY
|
||||
* KHRONOS_APIATTRIBUTES
|
||||
*
|
||||
* These may be used in function prototypes as:
|
||||
*
|
||||
* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
|
||||
* int arg1,
|
||||
* int arg2) KHRONOS_APIATTRIBUTES;
|
||||
*/
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APICALL
|
||||
*-------------------------------------------------------------------------
|
||||
* This precedes the return type of the function in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
# define KHRONOS_APICALL __declspec(dllimport)
|
||||
#elif defined (__SYMBIAN32__)
|
||||
# define KHRONOS_APICALL IMPORT_C
|
||||
#elif defined(__ANDROID__)
|
||||
# define KHRONOS_APICALL __attribute__((visibility("default")))
|
||||
#else
|
||||
# define KHRONOS_APICALL
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIENTRY
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the return type of the function and precedes the function
|
||||
* name in the function prototype.
|
||||
*/
|
||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
|
||||
/* Win32 but not WinCE */
|
||||
# define KHRONOS_APIENTRY __stdcall
|
||||
#else
|
||||
# define KHRONOS_APIENTRY
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* Definition of KHRONOS_APIATTRIBUTES
|
||||
*-------------------------------------------------------------------------
|
||||
* This follows the closing parenthesis of the function prototype arguments.
|
||||
*/
|
||||
#if defined (__ARMCC_2__)
|
||||
#define KHRONOS_APIATTRIBUTES __softfp
|
||||
#else
|
||||
#define KHRONOS_APIATTRIBUTES
|
||||
#endif
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* basic type definitions
|
||||
*-----------------------------------------------------------------------*/
|
||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
|
||||
|
||||
|
||||
/*
|
||||
* Using <stdint.h>
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__VMS ) || defined(__sgi)
|
||||
|
||||
/*
|
||||
* Using <inttypes.h>
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
|
||||
|
||||
/*
|
||||
* Win32
|
||||
*/
|
||||
typedef __int32 khronos_int32_t;
|
||||
typedef unsigned __int32 khronos_uint32_t;
|
||||
typedef __int64 khronos_int64_t;
|
||||
typedef unsigned __int64 khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif defined(__sun__) || defined(__digital__)
|
||||
|
||||
/*
|
||||
* Sun or Digital
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#if defined(__arch64__) || defined(_LP64)
|
||||
typedef long int khronos_int64_t;
|
||||
typedef unsigned long int khronos_uint64_t;
|
||||
#else
|
||||
typedef long long int khronos_int64_t;
|
||||
typedef unsigned long long int khronos_uint64_t;
|
||||
#endif /* __arch64__ */
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#elif 0
|
||||
|
||||
/*
|
||||
* Hypothetical platform with no float or int64 support
|
||||
*/
|
||||
typedef int khronos_int32_t;
|
||||
typedef unsigned int khronos_uint32_t;
|
||||
#define KHRONOS_SUPPORT_INT64 0
|
||||
#define KHRONOS_SUPPORT_FLOAT 0
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Generic fallback
|
||||
*/
|
||||
#include <stdint.h>
|
||||
typedef int32_t khronos_int32_t;
|
||||
typedef uint32_t khronos_uint32_t;
|
||||
typedef int64_t khronos_int64_t;
|
||||
typedef uint64_t khronos_uint64_t;
|
||||
#define KHRONOS_SUPPORT_INT64 1
|
||||
#define KHRONOS_SUPPORT_FLOAT 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Types that are (so far) the same on all platforms
|
||||
*/
|
||||
typedef signed char khronos_int8_t;
|
||||
typedef unsigned char khronos_uint8_t;
|
||||
typedef signed short int khronos_int16_t;
|
||||
typedef unsigned short int khronos_uint16_t;
|
||||
|
||||
/*
|
||||
* Types that differ between LLP64 and LP64 architectures - in LLP64,
|
||||
* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
|
||||
* to be the only LLP64 architecture in current use.
|
||||
*/
|
||||
#ifdef _WIN64
|
||||
typedef signed long long int khronos_intptr_t;
|
||||
typedef unsigned long long int khronos_uintptr_t;
|
||||
typedef signed long long int khronos_ssize_t;
|
||||
typedef unsigned long long int khronos_usize_t;
|
||||
#else
|
||||
typedef signed long int khronos_intptr_t;
|
||||
typedef unsigned long int khronos_uintptr_t;
|
||||
typedef signed long int khronos_ssize_t;
|
||||
typedef unsigned long int khronos_usize_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_FLOAT
|
||||
/*
|
||||
* Float type
|
||||
*/
|
||||
typedef float khronos_float_t;
|
||||
#endif
|
||||
|
||||
#if KHRONOS_SUPPORT_INT64
|
||||
/* Time types
|
||||
*
|
||||
* These types can be used to represent a time interval in nanoseconds or
|
||||
* an absolute Unadjusted System Time. Unadjusted System Time is the number
|
||||
* of nanoseconds since some arbitrary system event (e.g. since the last
|
||||
* time the system booted). The Unadjusted System Time is an unsigned
|
||||
* 64 bit value that wraps back to 0 every 584 years. Time intervals
|
||||
* may be either signed or unsigned.
|
||||
*/
|
||||
typedef khronos_uint64_t khronos_utime_nanoseconds_t;
|
||||
typedef khronos_int64_t khronos_stime_nanoseconds_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Dummy value used to pad enum types to 32 bits.
|
||||
*/
|
||||
#ifndef KHRONOS_MAX_ENUM
|
||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enumerated boolean type
|
||||
*
|
||||
* Values other than zero should be considered to be true. Therefore
|
||||
* comparisons should not be made against KHRONOS_TRUE.
|
||||
*/
|
||||
typedef enum {
|
||||
KHRONOS_FALSE = 0,
|
||||
KHRONOS_TRUE = 1,
|
||||
KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
|
||||
} khronos_boolean_enum_t;
|
||||
|
||||
#endif /* __khrplatform_h_ */
|
||||
@@ -0,0 +1,841 @@
|
||||
/*
|
||||
|
||||
This file was generated with gl3w_gen.py, part of gl3w
|
||||
(hosted at https://github.com/skaslev/gl3w)
|
||||
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <GL/gl3w.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
|
||||
static HMODULE libgl;
|
||||
static PROC (__stdcall *wgl_get_proc_address)(LPCSTR);
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = LoadLibraryA("opengl32.dll");
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
|
||||
*(void **)(&wgl_get_proc_address) = GetProcAddress(libgl, "wglGetProcAddress");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void)
|
||||
{
|
||||
FreeLibrary(libgl);
|
||||
}
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
|
||||
res = (GL3WglProc)wgl_get_proc_address(proc);
|
||||
if (!res)
|
||||
res = (GL3WglProc)GetProcAddress(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("/System/Library/Frameworks/OpenGL.framework/OpenGL", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void)
|
||||
{
|
||||
dlclose(libgl);
|
||||
}
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
|
||||
static void *libgl;
|
||||
static GL3WglProc (*glx_get_proc_address)(const GLubyte *);
|
||||
|
||||
static int open_libgl(void)
|
||||
{
|
||||
libgl = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!libgl)
|
||||
return GL3W_ERROR_LIBRARY_OPEN;
|
||||
|
||||
*(void **)(&glx_get_proc_address) = dlsym(libgl, "glXGetProcAddressARB");
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void close_libgl(void)
|
||||
{
|
||||
dlclose(libgl);
|
||||
}
|
||||
|
||||
static GL3WglProc get_proc(const char *proc)
|
||||
{
|
||||
GL3WglProc res;
|
||||
|
||||
res = glx_get_proc_address((const GLubyte *)proc);
|
||||
if (!res)
|
||||
*(void **)(&res) = dlsym(libgl, proc);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct {
|
||||
int major, minor;
|
||||
} version;
|
||||
|
||||
static int parse_version(void)
|
||||
{
|
||||
if (!glGetIntegerv)
|
||||
return GL3W_ERROR_INIT;
|
||||
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &version.major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &version.minor);
|
||||
|
||||
if (version.major < 3)
|
||||
return GL3W_ERROR_OPENGL_VERSION;
|
||||
return GL3W_OK;
|
||||
}
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc);
|
||||
|
||||
int gl3wInit(void)
|
||||
{
|
||||
int res = open_libgl();
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
atexit(close_libgl);
|
||||
return gl3wInit2(get_proc);
|
||||
}
|
||||
|
||||
int gl3wInit2(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
load_procs(proc);
|
||||
return parse_version();
|
||||
}
|
||||
|
||||
int gl3wIsSupported(int major, int minor)
|
||||
{
|
||||
if (major < 3)
|
||||
return 0;
|
||||
if (version.major == major)
|
||||
return version.minor >= minor;
|
||||
return version.major >= major;
|
||||
}
|
||||
|
||||
GL3WglProc gl3wGetProcAddress(const char *proc)
|
||||
{
|
||||
return get_proc(proc);
|
||||
}
|
||||
|
||||
static const char *proc_names[] = {
|
||||
"glActiveShaderProgram",
|
||||
"glActiveTexture",
|
||||
"glAttachShader",
|
||||
"glBeginConditionalRender",
|
||||
"glBeginQuery",
|
||||
"glBeginQueryIndexed",
|
||||
"glBeginTransformFeedback",
|
||||
"glBindAttribLocation",
|
||||
"glBindBuffer",
|
||||
"glBindBufferBase",
|
||||
"glBindBufferRange",
|
||||
"glBindBuffersBase",
|
||||
"glBindBuffersRange",
|
||||
"glBindFragDataLocation",
|
||||
"glBindFragDataLocationIndexed",
|
||||
"glBindFramebuffer",
|
||||
"glBindImageTexture",
|
||||
"glBindImageTextures",
|
||||
"glBindProgramPipeline",
|
||||
"glBindRenderbuffer",
|
||||
"glBindSampler",
|
||||
"glBindSamplers",
|
||||
"glBindTexture",
|
||||
"glBindTextureUnit",
|
||||
"glBindTextures",
|
||||
"glBindTransformFeedback",
|
||||
"glBindVertexArray",
|
||||
"glBindVertexBuffer",
|
||||
"glBindVertexBuffers",
|
||||
"glBlendColor",
|
||||
"glBlendEquation",
|
||||
"glBlendEquationSeparate",
|
||||
"glBlendEquationSeparatei",
|
||||
"glBlendEquationi",
|
||||
"glBlendFunc",
|
||||
"glBlendFuncSeparate",
|
||||
"glBlendFuncSeparatei",
|
||||
"glBlendFunci",
|
||||
"glBlitFramebuffer",
|
||||
"glBlitNamedFramebuffer",
|
||||
"glBufferData",
|
||||
"glBufferStorage",
|
||||
"glBufferSubData",
|
||||
"glCheckFramebufferStatus",
|
||||
"glCheckNamedFramebufferStatus",
|
||||
"glClampColor",
|
||||
"glClear",
|
||||
"glClearBufferData",
|
||||
"glClearBufferSubData",
|
||||
"glClearBufferfi",
|
||||
"glClearBufferfv",
|
||||
"glClearBufferiv",
|
||||
"glClearBufferuiv",
|
||||
"glClearColor",
|
||||
"glClearDepth",
|
||||
"glClearDepthf",
|
||||
"glClearNamedBufferData",
|
||||
"glClearNamedBufferSubData",
|
||||
"glClearNamedFramebufferfi",
|
||||
"glClearNamedFramebufferfv",
|
||||
"glClearNamedFramebufferiv",
|
||||
"glClearNamedFramebufferuiv",
|
||||
"glClearStencil",
|
||||
"glClearTexImage",
|
||||
"glClearTexSubImage",
|
||||
"glClientWaitSync",
|
||||
"glClipControl",
|
||||
"glColorMask",
|
||||
"glColorMaski",
|
||||
"glCompileShader",
|
||||
"glCompressedTexImage1D",
|
||||
"glCompressedTexImage2D",
|
||||
"glCompressedTexImage3D",
|
||||
"glCompressedTexSubImage1D",
|
||||
"glCompressedTexSubImage2D",
|
||||
"glCompressedTexSubImage3D",
|
||||
"glCompressedTextureSubImage1D",
|
||||
"glCompressedTextureSubImage2D",
|
||||
"glCompressedTextureSubImage3D",
|
||||
"glCopyBufferSubData",
|
||||
"glCopyImageSubData",
|
||||
"glCopyNamedBufferSubData",
|
||||
"glCopyTexImage1D",
|
||||
"glCopyTexImage2D",
|
||||
"glCopyTexSubImage1D",
|
||||
"glCopyTexSubImage2D",
|
||||
"glCopyTexSubImage3D",
|
||||
"glCopyTextureSubImage1D",
|
||||
"glCopyTextureSubImage2D",
|
||||
"glCopyTextureSubImage3D",
|
||||
"glCreateBuffers",
|
||||
"glCreateFramebuffers",
|
||||
"glCreateProgram",
|
||||
"glCreateProgramPipelines",
|
||||
"glCreateQueries",
|
||||
"glCreateRenderbuffers",
|
||||
"glCreateSamplers",
|
||||
"glCreateShader",
|
||||
"glCreateShaderProgramv",
|
||||
"glCreateTextures",
|
||||
"glCreateTransformFeedbacks",
|
||||
"glCreateVertexArrays",
|
||||
"glCullFace",
|
||||
"glDebugMessageCallback",
|
||||
"glDebugMessageControl",
|
||||
"glDebugMessageInsert",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteFramebuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteProgramPipelines",
|
||||
"glDeleteQueries",
|
||||
"glDeleteRenderbuffers",
|
||||
"glDeleteSamplers",
|
||||
"glDeleteShader",
|
||||
"glDeleteSync",
|
||||
"glDeleteTextures",
|
||||
"glDeleteTransformFeedbacks",
|
||||
"glDeleteVertexArrays",
|
||||
"glDepthFunc",
|
||||
"glDepthMask",
|
||||
"glDepthRange",
|
||||
"glDepthRangeArrayv",
|
||||
"glDepthRangeIndexed",
|
||||
"glDepthRangef",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDisableVertexArrayAttrib",
|
||||
"glDisableVertexAttribArray",
|
||||
"glDisablei",
|
||||
"glDispatchCompute",
|
||||
"glDispatchComputeIndirect",
|
||||
"glDrawArrays",
|
||||
"glDrawArraysIndirect",
|
||||
"glDrawArraysInstanced",
|
||||
"glDrawArraysInstancedBaseInstance",
|
||||
"glDrawBuffer",
|
||||
"glDrawBuffers",
|
||||
"glDrawElements",
|
||||
"glDrawElementsBaseVertex",
|
||||
"glDrawElementsIndirect",
|
||||
"glDrawElementsInstanced",
|
||||
"glDrawElementsInstancedBaseInstance",
|
||||
"glDrawElementsInstancedBaseVertex",
|
||||
"glDrawElementsInstancedBaseVertexBaseInstance",
|
||||
"glDrawRangeElements",
|
||||
"glDrawRangeElementsBaseVertex",
|
||||
"glDrawTransformFeedback",
|
||||
"glDrawTransformFeedbackInstanced",
|
||||
"glDrawTransformFeedbackStream",
|
||||
"glDrawTransformFeedbackStreamInstanced",
|
||||
"glEnable",
|
||||
"glEnableVertexArrayAttrib",
|
||||
"glEnableVertexAttribArray",
|
||||
"glEnablei",
|
||||
"glEndConditionalRender",
|
||||
"glEndQuery",
|
||||
"glEndQueryIndexed",
|
||||
"glEndTransformFeedback",
|
||||
"glFenceSync",
|
||||
"glFinish",
|
||||
"glFlush",
|
||||
"glFlushMappedBufferRange",
|
||||
"glFlushMappedNamedBufferRange",
|
||||
"glFramebufferParameteri",
|
||||
"glFramebufferRenderbuffer",
|
||||
"glFramebufferTexture",
|
||||
"glFramebufferTexture1D",
|
||||
"glFramebufferTexture2D",
|
||||
"glFramebufferTexture3D",
|
||||
"glFramebufferTextureLayer",
|
||||
"glFrontFace",
|
||||
"glGenBuffers",
|
||||
"glGenFramebuffers",
|
||||
"glGenProgramPipelines",
|
||||
"glGenQueries",
|
||||
"glGenRenderbuffers",
|
||||
"glGenSamplers",
|
||||
"glGenTextures",
|
||||
"glGenTransformFeedbacks",
|
||||
"glGenVertexArrays",
|
||||
"glGenerateMipmap",
|
||||
"glGenerateTextureMipmap",
|
||||
"glGetActiveAtomicCounterBufferiv",
|
||||
"glGetActiveAttrib",
|
||||
"glGetActiveSubroutineName",
|
||||
"glGetActiveSubroutineUniformName",
|
||||
"glGetActiveSubroutineUniformiv",
|
||||
"glGetActiveUniform",
|
||||
"glGetActiveUniformBlockName",
|
||||
"glGetActiveUniformBlockiv",
|
||||
"glGetActiveUniformName",
|
||||
"glGetActiveUniformsiv",
|
||||
"glGetAttachedShaders",
|
||||
"glGetAttribLocation",
|
||||
"glGetBooleani_v",
|
||||
"glGetBooleanv",
|
||||
"glGetBufferParameteri64v",
|
||||
"glGetBufferParameteriv",
|
||||
"glGetBufferPointerv",
|
||||
"glGetBufferSubData",
|
||||
"glGetCompressedTexImage",
|
||||
"glGetCompressedTextureImage",
|
||||
"glGetCompressedTextureSubImage",
|
||||
"glGetDebugMessageLog",
|
||||
"glGetDoublei_v",
|
||||
"glGetDoublev",
|
||||
"glGetError",
|
||||
"glGetFloati_v",
|
||||
"glGetFloatv",
|
||||
"glGetFragDataIndex",
|
||||
"glGetFragDataLocation",
|
||||
"glGetFramebufferAttachmentParameteriv",
|
||||
"glGetFramebufferParameteriv",
|
||||
"glGetGraphicsResetStatus",
|
||||
"glGetInteger64i_v",
|
||||
"glGetInteger64v",
|
||||
"glGetIntegeri_v",
|
||||
"glGetIntegerv",
|
||||
"glGetInternalformati64v",
|
||||
"glGetInternalformativ",
|
||||
"glGetMultisamplefv",
|
||||
"glGetNamedBufferParameteri64v",
|
||||
"glGetNamedBufferParameteriv",
|
||||
"glGetNamedBufferPointerv",
|
||||
"glGetNamedBufferSubData",
|
||||
"glGetNamedFramebufferAttachmentParameteriv",
|
||||
"glGetNamedFramebufferParameteriv",
|
||||
"glGetNamedRenderbufferParameteriv",
|
||||
"glGetObjectLabel",
|
||||
"glGetObjectPtrLabel",
|
||||
"glGetPointerv",
|
||||
"glGetProgramBinary",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetProgramInterfaceiv",
|
||||
"glGetProgramPipelineInfoLog",
|
||||
"glGetProgramPipelineiv",
|
||||
"glGetProgramResourceIndex",
|
||||
"glGetProgramResourceLocation",
|
||||
"glGetProgramResourceLocationIndex",
|
||||
"glGetProgramResourceName",
|
||||
"glGetProgramResourceiv",
|
||||
"glGetProgramStageiv",
|
||||
"glGetProgramiv",
|
||||
"glGetQueryBufferObjecti64v",
|
||||
"glGetQueryBufferObjectiv",
|
||||
"glGetQueryBufferObjectui64v",
|
||||
"glGetQueryBufferObjectuiv",
|
||||
"glGetQueryIndexediv",
|
||||
"glGetQueryObjecti64v",
|
||||
"glGetQueryObjectiv",
|
||||
"glGetQueryObjectui64v",
|
||||
"glGetQueryObjectuiv",
|
||||
"glGetQueryiv",
|
||||
"glGetRenderbufferParameteriv",
|
||||
"glGetSamplerParameterIiv",
|
||||
"glGetSamplerParameterIuiv",
|
||||
"glGetSamplerParameterfv",
|
||||
"glGetSamplerParameteriv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderPrecisionFormat",
|
||||
"glGetShaderSource",
|
||||
"glGetShaderiv",
|
||||
"glGetString",
|
||||
"glGetStringi",
|
||||
"glGetSubroutineIndex",
|
||||
"glGetSubroutineUniformLocation",
|
||||
"glGetSynciv",
|
||||
"glGetTexImage",
|
||||
"glGetTexLevelParameterfv",
|
||||
"glGetTexLevelParameteriv",
|
||||
"glGetTexParameterIiv",
|
||||
"glGetTexParameterIuiv",
|
||||
"glGetTexParameterfv",
|
||||
"glGetTexParameteriv",
|
||||
"glGetTextureImage",
|
||||
"glGetTextureLevelParameterfv",
|
||||
"glGetTextureLevelParameteriv",
|
||||
"glGetTextureParameterIiv",
|
||||
"glGetTextureParameterIuiv",
|
||||
"glGetTextureParameterfv",
|
||||
"glGetTextureParameteriv",
|
||||
"glGetTextureSubImage",
|
||||
"glGetTransformFeedbackVarying",
|
||||
"glGetTransformFeedbacki64_v",
|
||||
"glGetTransformFeedbacki_v",
|
||||
"glGetTransformFeedbackiv",
|
||||
"glGetUniformBlockIndex",
|
||||
"glGetUniformIndices",
|
||||
"glGetUniformLocation",
|
||||
"glGetUniformSubroutineuiv",
|
||||
"glGetUniformdv",
|
||||
"glGetUniformfv",
|
||||
"glGetUniformiv",
|
||||
"glGetUniformuiv",
|
||||
"glGetVertexArrayIndexed64iv",
|
||||
"glGetVertexArrayIndexediv",
|
||||
"glGetVertexArrayiv",
|
||||
"glGetVertexAttribIiv",
|
||||
"glGetVertexAttribIuiv",
|
||||
"glGetVertexAttribLdv",
|
||||
"glGetVertexAttribPointerv",
|
||||
"glGetVertexAttribdv",
|
||||
"glGetVertexAttribfv",
|
||||
"glGetVertexAttribiv",
|
||||
"glGetnCompressedTexImage",
|
||||
"glGetnTexImage",
|
||||
"glGetnUniformdv",
|
||||
"glGetnUniformfv",
|
||||
"glGetnUniformiv",
|
||||
"glGetnUniformuiv",
|
||||
"glHint",
|
||||
"glInvalidateBufferData",
|
||||
"glInvalidateBufferSubData",
|
||||
"glInvalidateFramebuffer",
|
||||
"glInvalidateNamedFramebufferData",
|
||||
"glInvalidateNamedFramebufferSubData",
|
||||
"glInvalidateSubFramebuffer",
|
||||
"glInvalidateTexImage",
|
||||
"glInvalidateTexSubImage",
|
||||
"glIsBuffer",
|
||||
"glIsEnabled",
|
||||
"glIsEnabledi",
|
||||
"glIsFramebuffer",
|
||||
"glIsProgram",
|
||||
"glIsProgramPipeline",
|
||||
"glIsQuery",
|
||||
"glIsRenderbuffer",
|
||||
"glIsSampler",
|
||||
"glIsShader",
|
||||
"glIsSync",
|
||||
"glIsTexture",
|
||||
"glIsTransformFeedback",
|
||||
"glIsVertexArray",
|
||||
"glLineWidth",
|
||||
"glLinkProgram",
|
||||
"glLogicOp",
|
||||
"glMapBuffer",
|
||||
"glMapBufferRange",
|
||||
"glMapNamedBuffer",
|
||||
"glMapNamedBufferRange",
|
||||
"glMemoryBarrier",
|
||||
"glMemoryBarrierByRegion",
|
||||
"glMinSampleShading",
|
||||
"glMultiDrawArrays",
|
||||
"glMultiDrawArraysIndirect",
|
||||
"glMultiDrawArraysIndirectCount",
|
||||
"glMultiDrawElements",
|
||||
"glMultiDrawElementsBaseVertex",
|
||||
"glMultiDrawElementsIndirect",
|
||||
"glMultiDrawElementsIndirectCount",
|
||||
"glNamedBufferData",
|
||||
"glNamedBufferStorage",
|
||||
"glNamedBufferSubData",
|
||||
"glNamedFramebufferDrawBuffer",
|
||||
"glNamedFramebufferDrawBuffers",
|
||||
"glNamedFramebufferParameteri",
|
||||
"glNamedFramebufferReadBuffer",
|
||||
"glNamedFramebufferRenderbuffer",
|
||||
"glNamedFramebufferTexture",
|
||||
"glNamedFramebufferTextureLayer",
|
||||
"glNamedRenderbufferStorage",
|
||||
"glNamedRenderbufferStorageMultisample",
|
||||
"glObjectLabel",
|
||||
"glObjectPtrLabel",
|
||||
"glPatchParameterfv",
|
||||
"glPatchParameteri",
|
||||
"glPauseTransformFeedback",
|
||||
"glPixelStoref",
|
||||
"glPixelStorei",
|
||||
"glPointParameterf",
|
||||
"glPointParameterfv",
|
||||
"glPointParameteri",
|
||||
"glPointParameteriv",
|
||||
"glPointSize",
|
||||
"glPolygonMode",
|
||||
"glPolygonOffset",
|
||||
"glPolygonOffsetClamp",
|
||||
"glPopDebugGroup",
|
||||
"glPrimitiveRestartIndex",
|
||||
"glProgramBinary",
|
||||
"glProgramParameteri",
|
||||
"glProgramUniform1d",
|
||||
"glProgramUniform1dv",
|
||||
"glProgramUniform1f",
|
||||
"glProgramUniform1fv",
|
||||
"glProgramUniform1i",
|
||||
"glProgramUniform1iv",
|
||||
"glProgramUniform1ui",
|
||||
"glProgramUniform1uiv",
|
||||
"glProgramUniform2d",
|
||||
"glProgramUniform2dv",
|
||||
"glProgramUniform2f",
|
||||
"glProgramUniform2fv",
|
||||
"glProgramUniform2i",
|
||||
"glProgramUniform2iv",
|
||||
"glProgramUniform2ui",
|
||||
"glProgramUniform2uiv",
|
||||
"glProgramUniform3d",
|
||||
"glProgramUniform3dv",
|
||||
"glProgramUniform3f",
|
||||
"glProgramUniform3fv",
|
||||
"glProgramUniform3i",
|
||||
"glProgramUniform3iv",
|
||||
"glProgramUniform3ui",
|
||||
"glProgramUniform3uiv",
|
||||
"glProgramUniform4d",
|
||||
"glProgramUniform4dv",
|
||||
"glProgramUniform4f",
|
||||
"glProgramUniform4fv",
|
||||
"glProgramUniform4i",
|
||||
"glProgramUniform4iv",
|
||||
"glProgramUniform4ui",
|
||||
"glProgramUniform4uiv",
|
||||
"glProgramUniformMatrix2dv",
|
||||
"glProgramUniformMatrix2fv",
|
||||
"glProgramUniformMatrix2x3dv",
|
||||
"glProgramUniformMatrix2x3fv",
|
||||
"glProgramUniformMatrix2x4dv",
|
||||
"glProgramUniformMatrix2x4fv",
|
||||
"glProgramUniformMatrix3dv",
|
||||
"glProgramUniformMatrix3fv",
|
||||
"glProgramUniformMatrix3x2dv",
|
||||
"glProgramUniformMatrix3x2fv",
|
||||
"glProgramUniformMatrix3x4dv",
|
||||
"glProgramUniformMatrix3x4fv",
|
||||
"glProgramUniformMatrix4dv",
|
||||
"glProgramUniformMatrix4fv",
|
||||
"glProgramUniformMatrix4x2dv",
|
||||
"glProgramUniformMatrix4x2fv",
|
||||
"glProgramUniformMatrix4x3dv",
|
||||
"glProgramUniformMatrix4x3fv",
|
||||
"glProvokingVertex",
|
||||
"glPushDebugGroup",
|
||||
"glQueryCounter",
|
||||
"glReadBuffer",
|
||||
"glReadPixels",
|
||||
"glReadnPixels",
|
||||
"glReleaseShaderCompiler",
|
||||
"glRenderbufferStorage",
|
||||
"glRenderbufferStorageMultisample",
|
||||
"glResumeTransformFeedback",
|
||||
"glSampleCoverage",
|
||||
"glSampleMaski",
|
||||
"glSamplerParameterIiv",
|
||||
"glSamplerParameterIuiv",
|
||||
"glSamplerParameterf",
|
||||
"glSamplerParameterfv",
|
||||
"glSamplerParameteri",
|
||||
"glSamplerParameteriv",
|
||||
"glScissor",
|
||||
"glScissorArrayv",
|
||||
"glScissorIndexed",
|
||||
"glScissorIndexedv",
|
||||
"glShaderBinary",
|
||||
"glShaderSource",
|
||||
"glShaderStorageBlockBinding",
|
||||
"glSpecializeShader",
|
||||
"glStencilFunc",
|
||||
"glStencilFuncSeparate",
|
||||
"glStencilMask",
|
||||
"glStencilMaskSeparate",
|
||||
"glStencilOp",
|
||||
"glStencilOpSeparate",
|
||||
"glTexBuffer",
|
||||
"glTexBufferRange",
|
||||
"glTexImage1D",
|
||||
"glTexImage2D",
|
||||
"glTexImage2DMultisample",
|
||||
"glTexImage3D",
|
||||
"glTexImage3DMultisample",
|
||||
"glTexParameterIiv",
|
||||
"glTexParameterIuiv",
|
||||
"glTexParameterf",
|
||||
"glTexParameterfv",
|
||||
"glTexParameteri",
|
||||
"glTexParameteriv",
|
||||
"glTexStorage1D",
|
||||
"glTexStorage2D",
|
||||
"glTexStorage2DMultisample",
|
||||
"glTexStorage3D",
|
||||
"glTexStorage3DMultisample",
|
||||
"glTexSubImage1D",
|
||||
"glTexSubImage2D",
|
||||
"glTexSubImage3D",
|
||||
"glTextureBarrier",
|
||||
"glTextureBuffer",
|
||||
"glTextureBufferRange",
|
||||
"glTextureParameterIiv",
|
||||
"glTextureParameterIuiv",
|
||||
"glTextureParameterf",
|
||||
"glTextureParameterfv",
|
||||
"glTextureParameteri",
|
||||
"glTextureParameteriv",
|
||||
"glTextureStorage1D",
|
||||
"glTextureStorage2D",
|
||||
"glTextureStorage2DMultisample",
|
||||
"glTextureStorage3D",
|
||||
"glTextureStorage3DMultisample",
|
||||
"glTextureSubImage1D",
|
||||
"glTextureSubImage2D",
|
||||
"glTextureSubImage3D",
|
||||
"glTextureView",
|
||||
"glTransformFeedbackBufferBase",
|
||||
"glTransformFeedbackBufferRange",
|
||||
"glTransformFeedbackVaryings",
|
||||
"glUniform1d",
|
||||
"glUniform1dv",
|
||||
"glUniform1f",
|
||||
"glUniform1fv",
|
||||
"glUniform1i",
|
||||
"glUniform1iv",
|
||||
"glUniform1ui",
|
||||
"glUniform1uiv",
|
||||
"glUniform2d",
|
||||
"glUniform2dv",
|
||||
"glUniform2f",
|
||||
"glUniform2fv",
|
||||
"glUniform2i",
|
||||
"glUniform2iv",
|
||||
"glUniform2ui",
|
||||
"glUniform2uiv",
|
||||
"glUniform3d",
|
||||
"glUniform3dv",
|
||||
"glUniform3f",
|
||||
"glUniform3fv",
|
||||
"glUniform3i",
|
||||
"glUniform3iv",
|
||||
"glUniform3ui",
|
||||
"glUniform3uiv",
|
||||
"glUniform4d",
|
||||
"glUniform4dv",
|
||||
"glUniform4f",
|
||||
"glUniform4fv",
|
||||
"glUniform4i",
|
||||
"glUniform4iv",
|
||||
"glUniform4ui",
|
||||
"glUniform4uiv",
|
||||
"glUniformBlockBinding",
|
||||
"glUniformMatrix2dv",
|
||||
"glUniformMatrix2fv",
|
||||
"glUniformMatrix2x3dv",
|
||||
"glUniformMatrix2x3fv",
|
||||
"glUniformMatrix2x4dv",
|
||||
"glUniformMatrix2x4fv",
|
||||
"glUniformMatrix3dv",
|
||||
"glUniformMatrix3fv",
|
||||
"glUniformMatrix3x2dv",
|
||||
"glUniformMatrix3x2fv",
|
||||
"glUniformMatrix3x4dv",
|
||||
"glUniformMatrix3x4fv",
|
||||
"glUniformMatrix4dv",
|
||||
"glUniformMatrix4fv",
|
||||
"glUniformMatrix4x2dv",
|
||||
"glUniformMatrix4x2fv",
|
||||
"glUniformMatrix4x3dv",
|
||||
"glUniformMatrix4x3fv",
|
||||
"glUniformSubroutinesuiv",
|
||||
"glUnmapBuffer",
|
||||
"glUnmapNamedBuffer",
|
||||
"glUseProgram",
|
||||
"glUseProgramStages",
|
||||
"glValidateProgram",
|
||||
"glValidateProgramPipeline",
|
||||
"glVertexArrayAttribBinding",
|
||||
"glVertexArrayAttribFormat",
|
||||
"glVertexArrayAttribIFormat",
|
||||
"glVertexArrayAttribLFormat",
|
||||
"glVertexArrayBindingDivisor",
|
||||
"glVertexArrayElementBuffer",
|
||||
"glVertexArrayVertexBuffer",
|
||||
"glVertexArrayVertexBuffers",
|
||||
"glVertexAttrib1d",
|
||||
"glVertexAttrib1dv",
|
||||
"glVertexAttrib1f",
|
||||
"glVertexAttrib1fv",
|
||||
"glVertexAttrib1s",
|
||||
"glVertexAttrib1sv",
|
||||
"glVertexAttrib2d",
|
||||
"glVertexAttrib2dv",
|
||||
"glVertexAttrib2f",
|
||||
"glVertexAttrib2fv",
|
||||
"glVertexAttrib2s",
|
||||
"glVertexAttrib2sv",
|
||||
"glVertexAttrib3d",
|
||||
"glVertexAttrib3dv",
|
||||
"glVertexAttrib3f",
|
||||
"glVertexAttrib3fv",
|
||||
"glVertexAttrib3s",
|
||||
"glVertexAttrib3sv",
|
||||
"glVertexAttrib4Nbv",
|
||||
"glVertexAttrib4Niv",
|
||||
"glVertexAttrib4Nsv",
|
||||
"glVertexAttrib4Nub",
|
||||
"glVertexAttrib4Nubv",
|
||||
"glVertexAttrib4Nuiv",
|
||||
"glVertexAttrib4Nusv",
|
||||
"glVertexAttrib4bv",
|
||||
"glVertexAttrib4d",
|
||||
"glVertexAttrib4dv",
|
||||
"glVertexAttrib4f",
|
||||
"glVertexAttrib4fv",
|
||||
"glVertexAttrib4iv",
|
||||
"glVertexAttrib4s",
|
||||
"glVertexAttrib4sv",
|
||||
"glVertexAttrib4ubv",
|
||||
"glVertexAttrib4uiv",
|
||||
"glVertexAttrib4usv",
|
||||
"glVertexAttribBinding",
|
||||
"glVertexAttribDivisor",
|
||||
"glVertexAttribFormat",
|
||||
"glVertexAttribI1i",
|
||||
"glVertexAttribI1iv",
|
||||
"glVertexAttribI1ui",
|
||||
"glVertexAttribI1uiv",
|
||||
"glVertexAttribI2i",
|
||||
"glVertexAttribI2iv",
|
||||
"glVertexAttribI2ui",
|
||||
"glVertexAttribI2uiv",
|
||||
"glVertexAttribI3i",
|
||||
"glVertexAttribI3iv",
|
||||
"glVertexAttribI3ui",
|
||||
"glVertexAttribI3uiv",
|
||||
"glVertexAttribI4bv",
|
||||
"glVertexAttribI4i",
|
||||
"glVertexAttribI4iv",
|
||||
"glVertexAttribI4sv",
|
||||
"glVertexAttribI4ubv",
|
||||
"glVertexAttribI4ui",
|
||||
"glVertexAttribI4uiv",
|
||||
"glVertexAttribI4usv",
|
||||
"glVertexAttribIFormat",
|
||||
"glVertexAttribIPointer",
|
||||
"glVertexAttribL1d",
|
||||
"glVertexAttribL1dv",
|
||||
"glVertexAttribL2d",
|
||||
"glVertexAttribL2dv",
|
||||
"glVertexAttribL3d",
|
||||
"glVertexAttribL3dv",
|
||||
"glVertexAttribL4d",
|
||||
"glVertexAttribL4dv",
|
||||
"glVertexAttribLFormat",
|
||||
"glVertexAttribLPointer",
|
||||
"glVertexAttribP1ui",
|
||||
"glVertexAttribP1uiv",
|
||||
"glVertexAttribP2ui",
|
||||
"glVertexAttribP2uiv",
|
||||
"glVertexAttribP3ui",
|
||||
"glVertexAttribP3uiv",
|
||||
"glVertexAttribP4ui",
|
||||
"glVertexAttribP4uiv",
|
||||
"glVertexAttribPointer",
|
||||
"glVertexBindingDivisor",
|
||||
"glViewport",
|
||||
"glViewportArrayv",
|
||||
"glViewportIndexedf",
|
||||
"glViewportIndexedfv",
|
||||
"glWaitSync",
|
||||
};
|
||||
|
||||
union GL3WProcs gl3wProcs;
|
||||
|
||||
static void load_procs(GL3WGetProcAddressProc proc)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
|
||||
gl3wProcs.ptr[i] = proc(proc_names[i]);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2002-2006 Marcus Geelnard
|
||||
Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would
|
||||
be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,456 @@
|
||||
/*************************************************************************
|
||||
* GLFW 3.2 - www.glfw.org
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _glfw3_native_h_
|
||||
#define _glfw3_native_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Doxygen documentation
|
||||
*************************************************************************/
|
||||
|
||||
/*! @file glfw3native.h
|
||||
* @brief The header of the native access functions.
|
||||
*
|
||||
* This is the header file of the native access functions. See @ref native for
|
||||
* more information.
|
||||
*/
|
||||
/*! @defgroup native Native access
|
||||
*
|
||||
* **By using the native access functions you assert that you know what you're
|
||||
* doing and how to fix problems caused by using them. If you don't, you
|
||||
* shouldn't be using them.**
|
||||
*
|
||||
* Before the inclusion of @ref glfw3native.h, you may define exactly one
|
||||
* window system API macro and zero or more context creation API macros.
|
||||
*
|
||||
* The chosen backends must match those the library was compiled for. Failure
|
||||
* to do this will cause a link-time error.
|
||||
*
|
||||
* The available window API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WIN32`
|
||||
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||
* * `GLFW_EXPOSE_NATIVE_MIR`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||
*
|
||||
* These macros select which of the native access functions that are declared
|
||||
* and which platform-specific headers to include. It is then up your (by
|
||||
* definition platform-specific) code to handle which of these should be
|
||||
* defined.
|
||||
*/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* System headers and types
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||
// example to allow applications to correctly declare a GL_ARB_debug_output
|
||||
// callback) but windows.h assumes no one will define APIENTRY before it does
|
||||
#undef APIENTRY
|
||||
#include <windows.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
#include <mir_toolkit/mir_client_library.h>
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/* WGL is declared by windows.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/* NSGL is declared by Cocoa.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Functions
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
/*! @brief Returns the adapter device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
|
||||
* of the specified monitor, or `NULL` if an [error](@ref error_handling)
|
||||
* occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the display device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded display device name (for example
|
||||
* `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `HWND` of the specified window.
|
||||
*
|
||||
* @return The `HWND` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/*! @brief Returns the `HGLRC` of the specified window.
|
||||
*
|
||||
* @return The `HGLRC` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
|
||||
*
|
||||
* @return The `CGDirectDisplayID` of the specified monitor, or
|
||||
* `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `NSWindow` of the specified window.
|
||||
*
|
||||
* @return The `NSWindow` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/*! @brief Returns the `NSOpenGLContext` of the specified window.
|
||||
*
|
||||
* @return The `NSOpenGLContext` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
/*! @brief Returns the `Display` used by GLFW.
|
||||
*
|
||||
* @return The `Display` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Display* glfwGetX11Display(void);
|
||||
|
||||
/*! @brief Returns the `RRCrtc` of the specified monitor.
|
||||
*
|
||||
* @return The `RRCrtc` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `RROutput` of the specified monitor.
|
||||
*
|
||||
* @return The `RROutput` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `Window` of the specified window.
|
||||
*
|
||||
* @return The `Window` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
/*! @brief Returns the `GLXContext` of the specified window.
|
||||
*
|
||||
* @return The `GLXContext` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `GLXWindow` of the specified window.
|
||||
*
|
||||
* @return The `GLXWindow` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
/*! @brief Returns the `struct wl_display*` used by GLFW.
|
||||
*
|
||||
* @return The `struct wl_display*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
|
||||
|
||||
/*! @brief Returns the `struct wl_output*` of the specified monitor.
|
||||
*
|
||||
* @return The `struct wl_output*` of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the main `struct wl_surface*` of the specified window.
|
||||
*
|
||||
* @return The main `struct wl_surface*` of the specified window, or `NULL` if
|
||||
* an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_MIR)
|
||||
/*! @brief Returns the `MirConnection*` used by GLFW.
|
||||
*
|
||||
* @return The `MirConnection*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirConnection* glfwGetMirDisplay(void);
|
||||
|
||||
/*! @brief Returns the Mir output ID of the specified monitor.
|
||||
*
|
||||
* @return The Mir output ID of the specified monitor, or zero if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `MirSurface*` of the specified window.
|
||||
*
|
||||
* @return The `MirSurface*` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||
*
|
||||
* @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
|
||||
|
||||
/*! @brief Returns the `EGLContext` of the specified window.
|
||||
*
|
||||
* @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `EGLSurface` of the specified window.
|
||||
*
|
||||
* @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _glfw3_native_h_ */
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2018 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,72 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
// A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h)
|
||||
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
|
||||
// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include
|
||||
// the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
//---- Define assertion handler. Defaults to calling assert().
|
||||
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
|
||||
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
|
||||
//---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty)
|
||||
//---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
|
||||
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
|
||||
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
|
||||
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free(). You will need to call ImGui::SetAllocatorFunctions().
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (if you needed to convert from one to another anyway)
|
||||
//#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of imgui cpp files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
|
||||
//---- Define constructor and implicit cast operators to convert back<>forth from your math types and ImVec2/ImVec4.
|
||||
// This will be inlined as part of ImVec2 and ImVec4 class declarations.
|
||||
/*
|
||||
#define IM_VEC2_CLASS_EXTRA \
|
||||
ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \
|
||||
operator MyVec2() const { return MyVec2(x,y); }
|
||||
|
||||
#define IM_VEC4_CLASS_EXTRA \
|
||||
ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \
|
||||
operator MyVec4() const { return MyVec4(x,y,z,w); }
|
||||
*/
|
||||
|
||||
//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it.
|
||||
//#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
}
|
||||
*/
|
||||
+13970
File diff suppressed because it is too large.
Load diff
+1928
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,301 @@
|
||||
// ImGui Platform Binding for: GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
|
||||
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples.
|
||||
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
|
||||
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()).
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
|
||||
// 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set.
|
||||
// 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
|
||||
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
|
||||
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
|
||||
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
// GLFW
|
||||
#include <GLFW/glfw3.h>
|
||||
#ifdef _WIN32
|
||||
#undef APIENTRY
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#include <GLFW/glfw3native.h> // for glfwGetWin32Window
|
||||
#endif
|
||||
#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING
|
||||
#define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED
|
||||
#define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity
|
||||
#define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale
|
||||
#define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface
|
||||
|
||||
// Data
|
||||
enum GlfwClientApi
|
||||
{
|
||||
GlfwClientApi_Unknown,
|
||||
GlfwClientApi_OpenGL,
|
||||
GlfwClientApi_Vulkan
|
||||
};
|
||||
static GLFWwindow* g_Window = NULL;
|
||||
static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown;
|
||||
static double g_Time = 0.0;
|
||||
static bool g_MouseJustPressed[5] = { false, false, false, false, false };
|
||||
static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 };
|
||||
static bool g_EnableMouseInput = true;
|
||||
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
{
|
||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow*, int button, int action, int /*mods*/)
|
||||
{
|
||||
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed))
|
||||
g_MouseJustPressed[button] = true;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow*, double xoffset, double yoffset)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.MouseWheelH += (float)xoffset;
|
||||
io.MouseWheel += (float)yoffset;
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_KeyCallback(GLFWwindow*, int key, int, int action, int mods)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (action == GLFW_PRESS)
|
||||
io.KeysDown[key] = true;
|
||||
if (action == GLFW_RELEASE)
|
||||
io.KeysDown[key] = false;
|
||||
|
||||
(void)mods; // Modifiers are not reliable across systems
|
||||
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
|
||||
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
|
||||
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
|
||||
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_CharCallback(GLFWwindow*, unsigned int c)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (c > 0 && c < 0x10000)
|
||||
io.AddInputCharacter((unsigned short)c);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
|
||||
{
|
||||
glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
|
||||
glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
|
||||
glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
|
||||
glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_SetReadMouseFromGlfw(bool enabled)
|
||||
{
|
||||
g_EnableMouseInput = enabled;
|
||||
}
|
||||
|
||||
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
|
||||
{
|
||||
g_Window = window;
|
||||
g_Time = 0.0;
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
|
||||
|
||||
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
||||
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
|
||||
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
|
||||
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
|
||||
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
|
||||
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
|
||||
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
|
||||
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
|
||||
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
|
||||
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
|
||||
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
|
||||
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
|
||||
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
|
||||
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
|
||||
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
|
||||
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
|
||||
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
|
||||
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
|
||||
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
|
||||
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = g_Window;
|
||||
#if defined(_WIN32)
|
||||
io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window);
|
||||
#endif
|
||||
|
||||
g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR);
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
|
||||
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this.
|
||||
|
||||
if (install_callbacks)
|
||||
ImGui_ImplGlfw_InstallCallbacks(window);
|
||||
|
||||
g_ClientApi = client_api;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL);
|
||||
}
|
||||
|
||||
bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks)
|
||||
{
|
||||
return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan);
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_Shutdown()
|
||||
{
|
||||
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
|
||||
{
|
||||
glfwDestroyCursor(g_MouseCursors[cursor_n]);
|
||||
g_MouseCursors[cursor_n] = NULL;
|
||||
}
|
||||
g_ClientApi = GlfwClientApi_Unknown;
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
|
||||
{
|
||||
if (!g_EnableMouseInput)
|
||||
return;
|
||||
|
||||
// Update buttons
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
|
||||
{
|
||||
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
||||
io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0;
|
||||
g_MouseJustPressed[i] = false;
|
||||
}
|
||||
|
||||
if (!glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
|
||||
return;
|
||||
|
||||
// Update mouse position
|
||||
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
if (io.WantSetMousePos)
|
||||
{
|
||||
glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double mouse_x, mouse_y;
|
||||
glfwGetCursorPos(g_Window, &mouse_x, &mouse_y);
|
||||
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_UpdateMouseCursor()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
|
||||
return;
|
||||
|
||||
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
|
||||
if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor)
|
||||
{
|
||||
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
||||
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show OS mouse cursor
|
||||
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||
glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||
glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_ImplGlfw_NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IM_ASSERT(io.Fonts->IsBuilt()); // Font atlas needs to be built, call renderer _NewFrame() function e.g. ImGui_ImplOpenGL3_NewFrame()
|
||||
|
||||
#if false // Rendering to our own framebuffer
|
||||
// Setup display size
|
||||
int w, h;
|
||||
int display_w, display_h;
|
||||
glfwGetWindowSize(g_Window, &w, &h);
|
||||
glfwGetFramebufferSize(g_Window, &display_w, &display_h);
|
||||
io.DisplaySize = ImVec2((float)w, (float)h);
|
||||
io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0);
|
||||
#endif
|
||||
|
||||
// Setup time step
|
||||
double current_time = glfwGetTime();
|
||||
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f);
|
||||
g_Time = current_time;
|
||||
|
||||
ImGui_ImplGlfw_UpdateMousePosAndButtons();
|
||||
ImGui_ImplGlfw_UpdateMouseCursor();
|
||||
|
||||
// Gamepad navigation mapping [BETA]
|
||||
memset(io.NavInputs, 0, sizeof(io.NavInputs));
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)
|
||||
{
|
||||
// Update gamepad inputs
|
||||
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
|
||||
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
|
||||
int axes_count = 0, buttons_count = 0;
|
||||
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
|
||||
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
|
||||
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
|
||||
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
|
||||
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
|
||||
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
|
||||
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
|
||||
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
|
||||
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
|
||||
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
|
||||
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
|
||||
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
|
||||
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
|
||||
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
|
||||
#undef MAP_BUTTON
|
||||
#undef MAP_ANALOG
|
||||
if (axes_count > 0 && buttons_count > 0)
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
else
|
||||
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// ImGui Platform Binding for: GLFW
|
||||
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..)
|
||||
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Platform: Clipboard support.
|
||||
// [X] Platform: Gamepad navigation mapping. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
|
||||
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown().
|
||||
// If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
|
||||
|
||||
// GLFW callbacks (installed by default if you enable 'install_callbacks' during initialization)
|
||||
// Provided here if you want to chain callbacks.
|
||||
// You can also handle inputs yourself and use those as a reference.
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c);
|
||||
|
||||
IMGUI_IMPL_API void ImGui_ImplGlfw_SetReadMouseFromGlfw(bool enabled);
|
||||
@@ -0,0 +1,319 @@
|
||||
// ImGui Renderer for: OpenGL3 (modern OpenGL with shaders / programmatic pipeline)
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
|
||||
// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
|
||||
// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer.
|
||||
// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
|
||||
// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
|
||||
// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
|
||||
// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
|
||||
// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
|
||||
// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include <GL/gl3w.h> // This example is using gl3w to access OpenGL functions. You may freely use any other OpenGL loader such as: glew, glad, glLoadGen, etc.
|
||||
//#include <glew.h>
|
||||
|
||||
// OpenGL Data
|
||||
static char g_GlslVersion[32] = "#version 150";
|
||||
static GLuint g_FontTexture = 0;
|
||||
static int g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
|
||||
static int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;
|
||||
static int g_AttribLocationPosition = 0, g_AttribLocationUV = 0, g_AttribLocationColor = 0;
|
||||
static unsigned int g_VboHandle = 0, g_ElementsHandle = 0;
|
||||
|
||||
// Functions
|
||||
bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
|
||||
{
|
||||
// Store GLSL version string so we can refer to it later in case we recreate shaders. Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure.
|
||||
if (glsl_version == NULL)
|
||||
glsl_version = "#version 150";
|
||||
IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersion));
|
||||
strcpy(g_GlslVersion, glsl_version);
|
||||
strcat(g_GlslVersion, "\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_Shutdown()
|
||||
{
|
||||
ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_NewFrame()
|
||||
{
|
||||
if (!g_FontTexture)
|
||||
ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
// OpenGL3 Render function.
|
||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||
// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
|
||||
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
|
||||
{
|
||||
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
int fb_width = (int)(draw_data->DisplaySize.x * io.DisplayFramebufferScale.x);
|
||||
int fb_height = (int)(draw_data->DisplaySize.y * io.DisplayFramebufferScale.y);
|
||||
if (fb_width <= 0 || fb_height <= 0)
|
||||
return;
|
||||
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
// Backup GL state
|
||||
GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program);
|
||||
GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler);
|
||||
GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
GLint last_vertex_array; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode);
|
||||
GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
|
||||
GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
|
||||
GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
|
||||
GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
|
||||
GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
|
||||
GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
|
||||
GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
|
||||
GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
|
||||
GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
|
||||
GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
|
||||
GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
|
||||
GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
glEnable(GL_BLEND);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin is typically (0,0) for single viewport apps.
|
||||
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
|
||||
float L = draw_data->DisplayPos.x;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
|
||||
float T = draw_data->DisplayPos.y;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
|
||||
const float ortho_projection[4][4] =
|
||||
{
|
||||
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
|
||||
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
|
||||
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||
{ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
|
||||
};
|
||||
glUseProgram(g_ShaderHandle);
|
||||
glUniform1i(g_AttribLocationTex, 0);
|
||||
glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
|
||||
if (glBindSampler) glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
|
||||
|
||||
// Recreate the VAO every time
|
||||
// (This is to easily allow multiple GL contexts. VAO are not shared among GL contexts, and we don't track creation/deletion of windows so we don't have an obvious key to use to cache them.)
|
||||
GLuint vao_handle = 0;
|
||||
glGenVertexArrays(1, &vao_handle);
|
||||
glBindVertexArray(vao_handle);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glEnableVertexAttribArray(g_AttribLocationPosition);
|
||||
glEnableVertexAttribArray(g_AttribLocationUV);
|
||||
glEnableVertexAttribArray(g_AttribLocationColor);
|
||||
glVertexAttribPointer(g_AttribLocationPosition, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos));
|
||||
glVertexAttribPointer(g_AttribLocationUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv));
|
||||
glVertexAttribPointer(g_AttribLocationColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col));
|
||||
|
||||
// Draw
|
||||
ImVec2 pos = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList* cmd_list = draw_data->CmdLists[n];
|
||||
const ImDrawIdx* idx_buffer_offset = 0;
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
|
||||
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
|
||||
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
|
||||
{
|
||||
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback)
|
||||
{
|
||||
// User callback (registered via ImDrawList::AddCallback)
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImVec4 clip_rect = ImVec4(pcmd->ClipRect.x - pos.x, pcmd->ClipRect.y - pos.y, pcmd->ClipRect.z - pos.x, pcmd->ClipRect.w - pos.y);
|
||||
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
|
||||
{
|
||||
// Apply scissor/clipping rectangle
|
||||
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
|
||||
|
||||
// Bind texture, Draw
|
||||
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId);
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
|
||||
}
|
||||
}
|
||||
idx_buffer_offset += pcmd->ElemCount;
|
||||
}
|
||||
}
|
||||
glDeleteVertexArrays(1, &vao_handle);
|
||||
|
||||
// Restore modified GL state
|
||||
glUseProgram(last_program);
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
if (glBindSampler) glBindSampler(0, last_sampler);
|
||||
glActiveTexture(last_active_texture);
|
||||
glBindVertexArray(last_vertex_array);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
|
||||
glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
|
||||
if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
|
||||
if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
|
||||
if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
|
||||
if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]);
|
||||
glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
|
||||
glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateFontsTexture()
|
||||
{
|
||||
// Build texture atlas
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char* pixels;
|
||||
int width, height;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
||||
|
||||
// Upload texture to graphics system
|
||||
GLint last_texture;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGenTextures(1, &g_FontTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (void *)(intptr_t)g_FontTexture;
|
||||
|
||||
// Restore state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyFontsTexture()
|
||||
{
|
||||
if (g_FontTexture)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
glDeleteTextures(1, &g_FontTexture);
|
||||
io.Fonts->TexID = 0;
|
||||
g_FontTexture = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
|
||||
{
|
||||
// Backup GL state
|
||||
GLint last_texture, last_array_buffer, last_vertex_array;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
|
||||
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
|
||||
|
||||
// Create shaders
|
||||
const GLchar *vertex_shader =
|
||||
"uniform mat4 ProjMtx;\n"
|
||||
"in vec2 Position;\n"
|
||||
"in vec2 UV;\n"
|
||||
"in vec4 Color;\n"
|
||||
"out vec2 Frag_UV;\n"
|
||||
"out vec4 Frag_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Frag_UV = UV;\n"
|
||||
" Frag_Color = Color;\n"
|
||||
" gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* fragment_shader =
|
||||
"uniform sampler2D Texture;\n"
|
||||
"in vec2 Frag_UV;\n"
|
||||
"in vec4 Frag_Color;\n"
|
||||
"layout(location = 0) out vec4 Out_Color;\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" Out_Color = Frag_Color * texture( Texture, Frag_UV.st);\n"
|
||||
"}\n";
|
||||
|
||||
const GLchar* vertex_shader_with_version[2] = { g_GlslVersion, vertex_shader };
|
||||
const GLchar* fragment_shader_with_version[2] = { g_GlslVersion, fragment_shader };
|
||||
|
||||
g_ShaderHandle = glCreateProgram();
|
||||
g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
|
||||
g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(g_VertHandle, 2, vertex_shader_with_version, NULL);
|
||||
glShaderSource(g_FragHandle, 2, fragment_shader_with_version, NULL);
|
||||
glCompileShader(g_VertHandle);
|
||||
glCompileShader(g_FragHandle);
|
||||
glAttachShader(g_ShaderHandle, g_VertHandle);
|
||||
glAttachShader(g_ShaderHandle, g_FragHandle);
|
||||
glLinkProgram(g_ShaderHandle);
|
||||
|
||||
g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
|
||||
g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
|
||||
g_AttribLocationPosition = glGetAttribLocation(g_ShaderHandle, "Position");
|
||||
g_AttribLocationUV = glGetAttribLocation(g_ShaderHandle, "UV");
|
||||
g_AttribLocationColor = glGetAttribLocation(g_ShaderHandle, "Color");
|
||||
|
||||
glGenBuffers(1, &g_VboHandle);
|
||||
glGenBuffers(1, &g_ElementsHandle);
|
||||
|
||||
ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
|
||||
// Restore modified GL state
|
||||
glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
|
||||
glBindVertexArray(last_vertex_array);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
|
||||
{
|
||||
if (g_VboHandle) glDeleteBuffers(1, &g_VboHandle);
|
||||
if (g_ElementsHandle) glDeleteBuffers(1, &g_ElementsHandle);
|
||||
g_VboHandle = g_ElementsHandle = 0;
|
||||
|
||||
if (g_ShaderHandle && g_VertHandle) glDetachShader(g_ShaderHandle, g_VertHandle);
|
||||
if (g_VertHandle) glDeleteShader(g_VertHandle);
|
||||
g_VertHandle = 0;
|
||||
|
||||
if (g_ShaderHandle && g_FragHandle) glDetachShader(g_ShaderHandle, g_FragHandle);
|
||||
if (g_FragHandle) glDeleteShader(g_FragHandle);
|
||||
g_FragHandle = 0;
|
||||
|
||||
if (g_ShaderHandle) glDeleteProgram(g_ShaderHandle);
|
||||
g_ShaderHandle = 0;
|
||||
|
||||
ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// ImGui Renderer for: OpenGL3 (modern OpenGL with shaders / programmatic pipeline)
|
||||
// This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..)
|
||||
// (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
|
||||
// About GLSL version:
|
||||
// The 'glsl_version' initialization parameter defaults to "#version 150" if NULL.
|
||||
// Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure!
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = "#version 150");
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data);
|
||||
|
||||
// Called by Init/NewFrame/Shutdown
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture();
|
||||
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,623 @@
|
||||
// stb_rect_pack.h - v0.11 - public domain - rectangle packing
|
||||
// Sean Barrett 2014
|
||||
//
|
||||
// Useful for e.g. packing rectangular textures into an atlas.
|
||||
// Does not do rotation.
|
||||
//
|
||||
// Not necessarily the awesomest packing method, but better than
|
||||
// the totally naive one in stb_truetype (which is primarily what
|
||||
// this is meant to replace).
|
||||
//
|
||||
// Has only had a few tests run, may have issues.
|
||||
//
|
||||
// More docs to come.
|
||||
//
|
||||
// No memory allocations; uses qsort() and assert() from stdlib.
|
||||
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
|
||||
//
|
||||
// This library currently uses the Skyline Bottom-Left algorithm.
|
||||
//
|
||||
// Please note: better rectangle packers are welcome! Please
|
||||
// implement them to the same API, but with a different init
|
||||
// function.
|
||||
//
|
||||
// Credits
|
||||
//
|
||||
// Library
|
||||
// Sean Barrett
|
||||
// Minor features
|
||||
// Martins Mozeiko
|
||||
// github:IntellectualKitty
|
||||
//
|
||||
// Bugfixes / warning fixes
|
||||
// Jeremy Jaussaud
|
||||
//
|
||||
// Version history:
|
||||
//
|
||||
// 0.11 (2017-03-03) return packing success/fail result
|
||||
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
|
||||
// 0.09 (2016-08-27) fix compiler warnings
|
||||
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
|
||||
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
|
||||
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
|
||||
// 0.05: added STBRP_ASSERT to allow replacing assert
|
||||
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
|
||||
// 0.01: initial release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDE SECTION
|
||||
//
|
||||
|
||||
#ifndef STB_INCLUDE_STB_RECT_PACK_H
|
||||
#define STB_INCLUDE_STB_RECT_PACK_H
|
||||
|
||||
#define STB_RECT_PACK_VERSION 1
|
||||
|
||||
#ifdef STBRP_STATIC
|
||||
#define STBRP_DEF static
|
||||
#else
|
||||
#define STBRP_DEF extern
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct stbrp_context stbrp_context;
|
||||
typedef struct stbrp_node stbrp_node;
|
||||
typedef struct stbrp_rect stbrp_rect;
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
typedef int stbrp_coord;
|
||||
#else
|
||||
typedef unsigned short stbrp_coord;
|
||||
#endif
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
|
||||
// Assign packed locations to rectangles. The rectangles are of type
|
||||
// 'stbrp_rect' defined below, stored in the array 'rects', and there
|
||||
// are 'num_rects' many of them.
|
||||
//
|
||||
// Rectangles which are successfully packed have the 'was_packed' flag
|
||||
// set to a non-zero value and 'x' and 'y' store the minimum location
|
||||
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
|
||||
// if you imagine y increasing downwards). Rectangles which do not fit
|
||||
// have the 'was_packed' flag set to 0.
|
||||
//
|
||||
// You should not try to access the 'rects' array from another thread
|
||||
// while this function is running, as the function temporarily reorders
|
||||
// the array while it executes.
|
||||
//
|
||||
// To pack into another rectangle, you need to call stbrp_init_target
|
||||
// again. To continue packing into the same rectangle, you can call
|
||||
// this function again. Calling this multiple times with multiple rect
|
||||
// arrays will probably produce worse packing results than calling it
|
||||
// a single time with the full rectangle array, but the option is
|
||||
// available.
|
||||
//
|
||||
// The function returns 1 if all of the rectangles were successfully
|
||||
// packed and 0 otherwise.
|
||||
|
||||
struct stbrp_rect
|
||||
{
|
||||
// reserved for your use:
|
||||
int id;
|
||||
|
||||
// input:
|
||||
stbrp_coord w, h;
|
||||
|
||||
// output:
|
||||
stbrp_coord x, y;
|
||||
int was_packed; // non-zero if valid packing
|
||||
|
||||
}; // 16 bytes, nominally
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
|
||||
// Initialize a rectangle packer to:
|
||||
// pack a rectangle that is 'width' by 'height' in dimensions
|
||||
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
|
||||
//
|
||||
// You must call this function every time you start packing into a new target.
|
||||
//
|
||||
// There is no "shutdown" function. The 'nodes' memory must stay valid for
|
||||
// the following stbrp_pack_rects() call (or calls), but can be freed after
|
||||
// the call (or calls) finish.
|
||||
//
|
||||
// Note: to guarantee best results, either:
|
||||
// 1. make sure 'num_nodes' >= 'width'
|
||||
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
|
||||
//
|
||||
// If you don't do either of the above things, widths will be quantized to multiples
|
||||
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
|
||||
//
|
||||
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
|
||||
// may run out of temporary storage and be unable to pack some rectangles.
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
|
||||
// Optionally call this function after init but before doing any packing to
|
||||
// change the handling of the out-of-temp-memory scenario, described above.
|
||||
// If you call init again, this will be reset to the default (false).
|
||||
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
|
||||
// Optionally select which packing heuristic the library should use. Different
|
||||
// heuristics will produce better/worse results for different data sets.
|
||||
// If you call init again, this will be reset to the default.
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP_HEURISTIC_Skyline_default=0,
|
||||
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
|
||||
STBRP_HEURISTIC_Skyline_BF_sortHeight
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// the details of the following structures don't matter to you, but they must
|
||||
// be visible so you can handle the memory allocations for them
|
||||
|
||||
struct stbrp_node
|
||||
{
|
||||
stbrp_coord x,y;
|
||||
stbrp_node *next;
|
||||
};
|
||||
|
||||
struct stbrp_context
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int align;
|
||||
int init_mode;
|
||||
int heuristic;
|
||||
int num_nodes;
|
||||
stbrp_node *active_head;
|
||||
stbrp_node *free_head;
|
||||
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPLEMENTATION SECTION
|
||||
//
|
||||
|
||||
#ifdef STB_RECT_PACK_IMPLEMENTATION
|
||||
#ifndef STBRP_SORT
|
||||
#include <stdlib.h>
|
||||
#define STBRP_SORT qsort
|
||||
#endif
|
||||
|
||||
#ifndef STBRP_ASSERT
|
||||
#include <assert.h>
|
||||
#define STBRP_ASSERT assert
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define STBRP__NOTUSED(v) (void)(v)
|
||||
#define STBRP__CDECL __cdecl
|
||||
#else
|
||||
#define STBRP__NOTUSED(v) (void)sizeof(v)
|
||||
#define STBRP__CDECL
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
STBRP__INIT_skyline = 1
|
||||
};
|
||||
|
||||
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
|
||||
{
|
||||
switch (context->init_mode) {
|
||||
case STBRP__INIT_skyline:
|
||||
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
|
||||
context->heuristic = heuristic;
|
||||
break;
|
||||
default:
|
||||
STBRP_ASSERT(0);
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
|
||||
{
|
||||
if (allow_out_of_mem)
|
||||
// if it's ok to run out of memory, then don't bother aligning them;
|
||||
// this gives better packing, but may fail due to OOM (even though
|
||||
// the rectangles easily fit). @TODO a smarter approach would be to only
|
||||
// quantize once we've hit OOM, then we could get rid of this parameter.
|
||||
context->align = 1;
|
||||
else {
|
||||
// if it's not ok to run out of memory, then quantize the widths
|
||||
// so that num_nodes is always enough nodes.
|
||||
//
|
||||
// I.e. num_nodes * align >= width
|
||||
// align >= width / num_nodes
|
||||
// align = ceil(width/num_nodes)
|
||||
|
||||
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
|
||||
}
|
||||
}
|
||||
|
||||
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
|
||||
{
|
||||
int i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
|
||||
#endif
|
||||
|
||||
for (i=0; i < num_nodes-1; ++i)
|
||||
nodes[i].next = &nodes[i+1];
|
||||
nodes[i].next = NULL;
|
||||
context->init_mode = STBRP__INIT_skyline;
|
||||
context->heuristic = STBRP_HEURISTIC_Skyline_default;
|
||||
context->free_head = &nodes[0];
|
||||
context->active_head = &context->extra[0];
|
||||
context->width = width;
|
||||
context->height = height;
|
||||
context->num_nodes = num_nodes;
|
||||
stbrp_setup_allow_out_of_mem(context, 0);
|
||||
|
||||
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
|
||||
context->extra[0].x = 0;
|
||||
context->extra[0].y = 0;
|
||||
context->extra[0].next = &context->extra[1];
|
||||
context->extra[1].x = (stbrp_coord) width;
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
context->extra[1].y = (1<<30);
|
||||
#else
|
||||
context->extra[1].y = 65535;
|
||||
#endif
|
||||
context->extra[1].next = NULL;
|
||||
}
|
||||
|
||||
// find minimum y position if it starts at x1
|
||||
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
|
||||
{
|
||||
stbrp_node *node = first;
|
||||
int x1 = x0 + width;
|
||||
int min_y, visited_width, waste_area;
|
||||
|
||||
STBRP__NOTUSED(c);
|
||||
|
||||
STBRP_ASSERT(first->x <= x0);
|
||||
|
||||
#if 0
|
||||
// skip in case we're past the node
|
||||
while (node->next->x <= x0)
|
||||
++node;
|
||||
#else
|
||||
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
|
||||
#endif
|
||||
|
||||
STBRP_ASSERT(node->x <= x0);
|
||||
|
||||
min_y = 0;
|
||||
waste_area = 0;
|
||||
visited_width = 0;
|
||||
while (node->x < x1) {
|
||||
if (node->y > min_y) {
|
||||
// raise min_y higher.
|
||||
// we've accounted for all waste up to min_y,
|
||||
// but we'll now add more waste for everything we've visted
|
||||
waste_area += visited_width * (node->y - min_y);
|
||||
min_y = node->y;
|
||||
// the first time through, visited_width might be reduced
|
||||
if (node->x < x0)
|
||||
visited_width += node->next->x - x0;
|
||||
else
|
||||
visited_width += node->next->x - node->x;
|
||||
} else {
|
||||
// add waste area
|
||||
int under_width = node->next->x - node->x;
|
||||
if (under_width + visited_width > width)
|
||||
under_width = width - visited_width;
|
||||
waste_area += under_width * (min_y - node->y);
|
||||
visited_width += under_width;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
*pwaste = waste_area;
|
||||
return min_y;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int x,y;
|
||||
stbrp_node **prev_link;
|
||||
} stbrp__findresult;
|
||||
|
||||
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
|
||||
{
|
||||
int best_waste = (1<<30), best_x, best_y = (1 << 30);
|
||||
stbrp__findresult fr;
|
||||
stbrp_node **prev, *node, *tail, **best = NULL;
|
||||
|
||||
// align to multiple of c->align
|
||||
width = (width + c->align - 1);
|
||||
width -= width % c->align;
|
||||
STBRP_ASSERT(width % c->align == 0);
|
||||
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
while (node->x + width <= c->width) {
|
||||
int y,waste;
|
||||
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
|
||||
// bottom left
|
||||
if (y < best_y) {
|
||||
best_y = y;
|
||||
best = prev;
|
||||
}
|
||||
} else {
|
||||
// best-fit
|
||||
if (y + height <= c->height) {
|
||||
// can only use it if it first vertically
|
||||
if (y < best_y || (y == best_y && waste < best_waste)) {
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
best_x = (best == NULL) ? 0 : (*best)->x;
|
||||
|
||||
// if doing best-fit (BF), we also have to try aligning right edge to each node position
|
||||
//
|
||||
// e.g, if fitting
|
||||
//
|
||||
// ____________________
|
||||
// |____________________|
|
||||
//
|
||||
// into
|
||||
//
|
||||
// | |
|
||||
// | ____________|
|
||||
// |____________|
|
||||
//
|
||||
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
|
||||
//
|
||||
// This makes BF take about 2x the time
|
||||
|
||||
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
|
||||
tail = c->active_head;
|
||||
node = c->active_head;
|
||||
prev = &c->active_head;
|
||||
// find first node that's admissible
|
||||
while (tail->x < width)
|
||||
tail = tail->next;
|
||||
while (tail) {
|
||||
int xpos = tail->x - width;
|
||||
int y,waste;
|
||||
STBRP_ASSERT(xpos >= 0);
|
||||
// find the left position that matches this
|
||||
while (node->next->x <= xpos) {
|
||||
prev = &node->next;
|
||||
node = node->next;
|
||||
}
|
||||
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
|
||||
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
|
||||
if (y + height < c->height) {
|
||||
if (y <= best_y) {
|
||||
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
|
||||
best_x = xpos;
|
||||
STBRP_ASSERT(y <= best_y);
|
||||
best_y = y;
|
||||
best_waste = waste;
|
||||
best = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
tail = tail->next;
|
||||
}
|
||||
}
|
||||
|
||||
fr.prev_link = best;
|
||||
fr.x = best_x;
|
||||
fr.y = best_y;
|
||||
return fr;
|
||||
}
|
||||
|
||||
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
|
||||
{
|
||||
// find best position according to heuristic
|
||||
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
|
||||
stbrp_node *node, *cur;
|
||||
|
||||
// bail if:
|
||||
// 1. it failed
|
||||
// 2. the best node doesn't fit (we don't always check this)
|
||||
// 3. we're out of memory
|
||||
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
|
||||
res.prev_link = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
// on success, create new node
|
||||
node = context->free_head;
|
||||
node->x = (stbrp_coord) res.x;
|
||||
node->y = (stbrp_coord) (res.y + height);
|
||||
|
||||
context->free_head = node->next;
|
||||
|
||||
// insert the new node into the right starting point, and
|
||||
// let 'cur' point to the remaining nodes needing to be
|
||||
// stiched back in
|
||||
|
||||
cur = *res.prev_link;
|
||||
if (cur->x < res.x) {
|
||||
// preserve the existing one, so start testing with the next one
|
||||
stbrp_node *next = cur->next;
|
||||
cur->next = node;
|
||||
cur = next;
|
||||
} else {
|
||||
*res.prev_link = node;
|
||||
}
|
||||
|
||||
// from here, traverse cur and free the nodes, until we get to one
|
||||
// that shouldn't be freed
|
||||
while (cur->next && cur->next->x <= res.x + width) {
|
||||
stbrp_node *next = cur->next;
|
||||
// move the current node to the free list
|
||||
cur->next = context->free_head;
|
||||
context->free_head = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
// stitch the list back in
|
||||
node->next = cur;
|
||||
|
||||
if (cur->x < res.x + width)
|
||||
cur->x = (stbrp_coord) (res.x + width);
|
||||
|
||||
#ifdef _DEBUG
|
||||
cur = context->active_head;
|
||||
while (cur->x < context->width) {
|
||||
STBRP_ASSERT(cur->x < cur->next->x);
|
||||
cur = cur->next;
|
||||
}
|
||||
STBRP_ASSERT(cur->next == NULL);
|
||||
|
||||
{
|
||||
int count=0;
|
||||
cur = context->active_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
cur = context->free_head;
|
||||
while (cur) {
|
||||
cur = cur->next;
|
||||
++count;
|
||||
}
|
||||
STBRP_ASSERT(count == context->num_nodes+2);
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
if (p->h > q->h)
|
||||
return -1;
|
||||
if (p->h < q->h)
|
||||
return 1;
|
||||
return (p->w > q->w) ? -1 : (p->w < q->w);
|
||||
}
|
||||
|
||||
static int STBRP__CDECL rect_original_order(const void *a, const void *b)
|
||||
{
|
||||
const stbrp_rect *p = (const stbrp_rect *) a;
|
||||
const stbrp_rect *q = (const stbrp_rect *) b;
|
||||
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
|
||||
}
|
||||
|
||||
#ifdef STBRP_LARGE_RECTS
|
||||
#define STBRP__MAXVAL 0xffffffff
|
||||
#else
|
||||
#define STBRP__MAXVAL 0xffff
|
||||
#endif
|
||||
|
||||
STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
|
||||
{
|
||||
int i, all_rects_packed = 1;
|
||||
|
||||
// we use the 'was_packed' field internally to allow sorting/unsorting
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = i;
|
||||
#ifndef STBRP_LARGE_RECTS
|
||||
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
|
||||
#endif
|
||||
}
|
||||
|
||||
// sort according to heuristic
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
|
||||
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
if (rects[i].w == 0 || rects[i].h == 0) {
|
||||
rects[i].x = rects[i].y = 0; // empty rect needs no space
|
||||
} else {
|
||||
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
|
||||
if (fr.prev_link) {
|
||||
rects[i].x = (stbrp_coord) fr.x;
|
||||
rects[i].y = (stbrp_coord) fr.y;
|
||||
} else {
|
||||
rects[i].x = rects[i].y = STBRP__MAXVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsort
|
||||
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
|
||||
|
||||
// set was_packed flags and all_rects_packed status
|
||||
for (i=0; i < num_rects; ++i) {
|
||||
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
|
||||
if (!rects[i].was_packed)
|
||||
all_rects_packed = 0;
|
||||
}
|
||||
|
||||
// return the all_rects_packed status
|
||||
return all_rects_packed;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,484 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "vrinputemulator_types.h"
|
||||
#include <utility>
|
||||
|
||||
|
||||
#define IPC_PROTOCOL_VERSION 3
|
||||
|
||||
namespace vrinputemulator {
|
||||
namespace ipc {
|
||||
|
||||
|
||||
enum class RequestType : uint32_t {
|
||||
None,
|
||||
|
||||
// IPC connection handling
|
||||
IPC_ClientConnect,
|
||||
IPC_ClientDisconnect,
|
||||
IPC_Ping,
|
||||
|
||||
// These are indented to inject events into OpenVR and require an OpenVR device id.
|
||||
// These are "fire and forget".
|
||||
OpenVR_PoseUpdate,
|
||||
OpenVR_ButtonEvent,
|
||||
OpenVR_AxisEvent,
|
||||
OpenVR_ProximitySensorEvent,
|
||||
OpenVR_VendorSpecificEvent,
|
||||
|
||||
// These are indented to manage virtual devices and require the internal device id.
|
||||
// The Reply is send to the client's message queue.
|
||||
VirtualDevices_AddDevice,
|
||||
VirtualDevices_PublishDevice,
|
||||
VirtualDevices_GetDeviceCount,
|
||||
VirtualDevices_GetDeviceInfo,
|
||||
VirtualDevices_GetDevicePose,
|
||||
VirtualDevices_GetControllerState,
|
||||
VirtualDevices_SetDeviceProperty,
|
||||
VirtualDevices_RemoveDeviceProperty,
|
||||
VirtualDevices_SetDevicePose,
|
||||
VirtualDevices_SetControllerState,
|
||||
|
||||
DeviceManipulation_GetDeviceInfo,
|
||||
DeviceManipulation_ButtonMapping,
|
||||
DeviceManipulation_GetDeviceOffsets,
|
||||
DeviceManipulation_SetDeviceOffsets,
|
||||
DeviceManipulation_DefaultMode,
|
||||
DeviceManipulation_RedirectMode,
|
||||
DeviceManipulation_SwapMode,
|
||||
DeviceManipulation_MotionCompensationMode,
|
||||
DeviceManipulation_FakeDisconnectedMode,
|
||||
DeviceManipulation_TriggerHapticPulse,
|
||||
DeviceManipulation_SetMotionCompensationProperties,
|
||||
|
||||
InputRemapping_SetDigitalRemapping,
|
||||
InputRemapping_GetDigitalRemapping,
|
||||
InputRemapping_SetAnalogRemapping,
|
||||
InputRemapping_GetAnalogRemapping,
|
||||
InputRemapping_SetTouchpadEmulationFixEnabled
|
||||
};
|
||||
|
||||
|
||||
enum class ReplyType : uint32_t {
|
||||
None,
|
||||
|
||||
IPC_ClientConnect,
|
||||
IPC_Ping,
|
||||
|
||||
GenericReply,
|
||||
|
||||
VirtualDevices_GetDeviceCount,
|
||||
VirtualDevices_GetDeviceInfo,
|
||||
VirtualDevices_GetDevicePose,
|
||||
VirtualDevices_GetControllerState,
|
||||
VirtualDevices_AddDevice,
|
||||
|
||||
DeviceManipulation_GetDeviceInfo,
|
||||
DeviceManipulation_GetDeviceOffsets,
|
||||
|
||||
InputRemapping_GetDigitalRemapping,
|
||||
InputRemapping_GetAnalogRemapping
|
||||
};
|
||||
|
||||
|
||||
enum class ReplyStatus : uint32_t {
|
||||
None,
|
||||
Ok,
|
||||
UnknownError,
|
||||
InvalidId,
|
||||
AlreadyInUse,
|
||||
InvalidType,
|
||||
NotFound,
|
||||
TooManyDevices,
|
||||
InvalidVersion,
|
||||
MissingProperty,
|
||||
InvalidOperation,
|
||||
NotTracking
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_ClientConnect {
|
||||
uint32_t messageId;
|
||||
uint32_t ipcProcotolVersion;
|
||||
char queueName[128];
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_ClientDisconnect {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId;
|
||||
};
|
||||
|
||||
|
||||
struct Request_IPC_Ping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId;
|
||||
uint64_t nonce;
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_PoseUpdate {
|
||||
uint32_t deviceId;
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
|
||||
#define REQUEST_OPENVR_BUTTONEVENT_MAXCOUNT 12
|
||||
|
||||
struct Request_OpenVR_ButtonEvent {
|
||||
unsigned eventCount;
|
||||
struct {
|
||||
ButtonEventType eventType;
|
||||
uint32_t deviceId;
|
||||
vr::EVRButtonId buttonId;
|
||||
double timeOffset;
|
||||
} events[REQUEST_OPENVR_BUTTONEVENT_MAXCOUNT];
|
||||
};
|
||||
|
||||
|
||||
#define REQUEST_OPENVR_AXISEVENT_MAXCOUNT 12
|
||||
|
||||
struct Request_OpenVR_AxisEvent {
|
||||
unsigned eventCount;
|
||||
struct {
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
vr::VRControllerAxis_t axisState;
|
||||
} events[REQUEST_OPENVR_AXISEVENT_MAXCOUNT];
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_ProximitySensorEvent {
|
||||
uint32_t deviceId;
|
||||
bool sensorTriggered;
|
||||
};
|
||||
|
||||
|
||||
struct Request_OpenVR_VendorSpecificEvent {
|
||||
uint32_t deviceId;
|
||||
vr::EVREventType eventType;
|
||||
vr::VREvent_Data_t eventData;
|
||||
double timeOffset;
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_GenericClientMessage {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_GenericDeviceIdMessage {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_AddDevice {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
VirtualDeviceType deviceType;
|
||||
char deviceSerial[256];
|
||||
};
|
||||
|
||||
|
||||
struct Request_VirtualDevices_SetDeviceProperty {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::ETrackedDeviceProperty deviceProperty;
|
||||
DevicePropertyValueType valueType;
|
||||
union {
|
||||
int32_t int32Value;
|
||||
uint64_t uint64Value;
|
||||
float floatValue;
|
||||
bool boolValue;
|
||||
char stringValue[256];
|
||||
vr::HmdMatrix34_t matrix34Value;
|
||||
vr::HmdMatrix44_t matrix44Value;
|
||||
vr::HmdVector3_t vector3Value;
|
||||
vr::HmdVector4_t vector4Value;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_RemoveDeviceProperty {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::ETrackedDeviceProperty deviceProperty;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_SetDevicePose {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
struct Request_VirtualDevices_SetControllerState {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t virtualDeviceId;
|
||||
vr::VRControllerState_t controllerState;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_ButtonMapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t enableMapping; // 0 .. don't change, 1 .. enable, 2 .. disable
|
||||
uint32_t mappingOperation; // 0 .. do nothing, 1 .. add given mappings, 2 .. remove given mappings, 3 .. remove all mappings
|
||||
uint32_t mappingCount;
|
||||
vr::EVRButtonId buttonMappings[32];
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SetDeviceOffsets {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t enableOffsets; // 0 .. don't change, 1 .. enable, 2 .. disable
|
||||
uint32_t offsetOperation; // 0 .. set, 1 .. add
|
||||
// world-from-driver universe offsets
|
||||
bool worldFromDriverRotationOffsetValid;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
bool worldFromDriverTranslationOffsetValid;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
// driver-from-head universe offsets
|
||||
bool driverFromHeadRotationOffsetValid;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
bool driverFromHeadTranslationOffsetValid;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
// device offsets
|
||||
bool deviceRotationOffsetValid;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
bool deviceTranslationOffsetValid;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_RedirectMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t targetId;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SwapMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t targetId;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_MotionCompensationMode {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
MotionCompensationVelAccMode velAccCompensationMode;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_TriggerHapticPulse {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
uint16_t durationMicroseconds;
|
||||
bool directMode;
|
||||
};
|
||||
|
||||
struct Request_DeviceManipulation_SetMotionCompensationProperties {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
bool velAccCompensationModeValid;
|
||||
MotionCompensationVelAccMode velAccCompensationMode;
|
||||
bool kalmanFilterProcessNoiseValid;
|
||||
double kalmanFilterProcessNoise;
|
||||
bool kalmanFilterObservationNoiseValid;
|
||||
double kalmanFilterObservationNoise;
|
||||
bool movingAverageWindowValid;
|
||||
unsigned movingAverageWindow;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetDigitalRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
DigitalInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_GetDigitalRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetAnalogRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t axisId;
|
||||
AnalogInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_GetAnalogRemapping {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
uint32_t controllerId;
|
||||
uint32_t axisId;
|
||||
};
|
||||
|
||||
struct Request_InputRemapping_SetTouchpadEmulationFixEnabled {
|
||||
uint32_t clientId;
|
||||
uint32_t messageId; // Used to associate with Reply
|
||||
bool enable;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Request {
|
||||
Request() {}
|
||||
Request(RequestType type) : type(type) {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
Request(RequestType type, uint64_t timestamp) : type(type), timestamp(timestamp) {}
|
||||
|
||||
void refreshTimestamp() {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
RequestType type = RequestType::None;
|
||||
int64_t timestamp = 0; // milliseconds since epoch
|
||||
union MsgUnion {
|
||||
Request_IPC_ClientConnect ipc_ClientConnect;
|
||||
Request_IPC_ClientDisconnect ipc_ClientDisconnect;
|
||||
Request_IPC_Ping ipc_Ping;
|
||||
Request_OpenVR_PoseUpdate ipc_PoseUpdate;
|
||||
Request_OpenVR_ButtonEvent ipc_ButtonEvent;
|
||||
Request_OpenVR_AxisEvent ipc_AxisEvent;
|
||||
Request_OpenVR_ProximitySensorEvent ovr_ProximitySensorEvent;
|
||||
Request_OpenVR_VendorSpecificEvent ovr_VendorSpecificEvent;
|
||||
Request_VirtualDevices_GenericClientMessage vd_GenericClientMessage;
|
||||
Request_VirtualDevices_GenericDeviceIdMessage vd_GenericDeviceIdMessage;
|
||||
Request_VirtualDevices_AddDevice vd_AddDevice;
|
||||
Request_VirtualDevices_SetDeviceProperty vd_SetDeviceProperty;
|
||||
Request_VirtualDevices_RemoveDeviceProperty vd_RemoveDeviceProperty;
|
||||
Request_VirtualDevices_SetDevicePose vd_SetDevicePose;
|
||||
Request_VirtualDevices_SetControllerState vd_SetControllerState;
|
||||
Request_DeviceManipulation_ButtonMapping dm_ButtonMapping;
|
||||
Request_DeviceManipulation_SetDeviceOffsets dm_DeviceOffsets;
|
||||
Request_DeviceManipulation_RedirectMode dm_RedirectMode;
|
||||
Request_DeviceManipulation_SwapMode dm_SwapMode;
|
||||
Request_DeviceManipulation_MotionCompensationMode dm_MotionCompensationMode;
|
||||
Request_DeviceManipulation_TriggerHapticPulse dm_triggerHapticPulse;
|
||||
Request_DeviceManipulation_SetMotionCompensationProperties dm_SetMotionCompensationProperties;
|
||||
Request_InputRemapping_SetDigitalRemapping ir_SetDigitalRemapping;
|
||||
Request_InputRemapping_GetDigitalRemapping ir_GetDigitalRemapping;
|
||||
Request_InputRemapping_SetAnalogRemapping ir_SetAnalogRemapping;
|
||||
Request_InputRemapping_GetAnalogRemapping ir_GetAnalogRemapping;
|
||||
Request_InputRemapping_SetTouchpadEmulationFixEnabled ir_SetTouchPadEmulationFixEnabled;
|
||||
MsgUnion() {}
|
||||
} msg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Reply_IPC_ClientConnect {
|
||||
uint32_t clientId;
|
||||
uint32_t ipcProcotolVersion;
|
||||
};
|
||||
|
||||
struct Reply_IPC_Ping {
|
||||
uint64_t nonce;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDeviceCount {
|
||||
uint32_t deviceCount;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDeviceInfo {
|
||||
uint32_t virtualDeviceId;
|
||||
uint32_t openvrDeviceId;
|
||||
VirtualDeviceType deviceType;
|
||||
char deviceSerial[128];
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetDevicePose {
|
||||
vr::DriverPose_t pose;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_GetControllerState {
|
||||
vr::VRControllerState_t controllerState;
|
||||
};
|
||||
|
||||
struct Reply_VirtualDevices_AddDevice {
|
||||
uint32_t virtualDeviceId;
|
||||
};
|
||||
|
||||
|
||||
struct Reply_DeviceManipulation_GetDeviceInfo {
|
||||
uint32_t deviceId;
|
||||
vr::ETrackedDeviceClass deviceClass;
|
||||
int deviceMode;
|
||||
uint32_t refDeviceId;
|
||||
bool offsetsEnabled;
|
||||
bool redirectSuspended;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct Reply_DeviceManipulation_GetDeviceOffsets {
|
||||
uint32_t deviceId;
|
||||
bool offsetsEnabled;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
struct Reply_InputRemapping_GetDigitalRemapping {
|
||||
uint32_t deviceId;
|
||||
uint32_t buttonId;
|
||||
DigitalInputRemapping remapData;
|
||||
};
|
||||
|
||||
struct Reply_InputRemapping_GetAnalogRemapping {
|
||||
uint32_t deviceId;
|
||||
uint32_t axisId;
|
||||
AnalogInputRemapping remapData;
|
||||
};
|
||||
|
||||
|
||||
struct Reply {
|
||||
Reply() {}
|
||||
Reply(ReplyType type) : type(type) {
|
||||
timestamp = std::chrono::duration_cast <std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
Reply(ReplyType type, uint64_t timestamp) : type(type), timestamp(timestamp) {}
|
||||
|
||||
ReplyType type = ReplyType::None;
|
||||
uint64_t timestamp = 0; // milliseconds since epoch
|
||||
uint32_t messageId;
|
||||
ReplyStatus status;
|
||||
union MsgUnion {
|
||||
Reply_IPC_ClientConnect ipc_ClientConnect;
|
||||
Reply_IPC_Ping ipc_Ping;
|
||||
Reply_VirtualDevices_GetDeviceCount vd_GetDeviceCount;
|
||||
Reply_VirtualDevices_GetDeviceInfo vd_GetDeviceInfo;
|
||||
Reply_VirtualDevices_GetDevicePose vd_GetDevicePose;
|
||||
Reply_VirtualDevices_GetControllerState vd_GetControllerState;
|
||||
Reply_VirtualDevices_AddDevice vd_AddDevice;
|
||||
Reply_DeviceManipulation_GetDeviceInfo dm_deviceInfo;
|
||||
Reply_DeviceManipulation_GetDeviceOffsets dm_deviceOffsets;
|
||||
Reply_InputRemapping_GetDigitalRemapping ir_getDigitalRemapping;
|
||||
Reply_InputRemapping_GetAnalogRemapping ir_getAnalogRemapping;
|
||||
MsgUnion() {}
|
||||
} msg;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace ipc
|
||||
} // end namespace vrinputemulator
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,229 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <openvr.h>
|
||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
|
||||
|
||||
namespace vr {
|
||||
// Copied from openvr_driver.h
|
||||
struct DriverPose_t {
|
||||
/* Time offset of this pose, in seconds from the actual time of the pose,
|
||||
* relative to the time of the PoseUpdated() call made by the driver.
|
||||
*/
|
||||
double poseTimeOffset;
|
||||
|
||||
/* Generally, the pose maintained by a driver
|
||||
* is in an inertial coordinate system different
|
||||
* from the world system of x+ right, y+ up, z+ back.
|
||||
* Also, the driver is not usually tracking the "head" position,
|
||||
* but instead an internal IMU or another reference point in the HMD.
|
||||
* The following two transforms transform positions and orientations
|
||||
* to app world space from driver world space,
|
||||
* and to HMD head space from driver local body space.
|
||||
*
|
||||
* We maintain the driver pose state in its internal coordinate system,
|
||||
* so we can do the pose prediction math without having to
|
||||
* use angular acceleration. A driver's angular acceleration is generally not measured,
|
||||
* and is instead calculated from successive samples of angular velocity.
|
||||
* This leads to a noisy angular acceleration values, which are also
|
||||
* lagged due to the filtering required to reduce noise to an acceptable level.
|
||||
*/
|
||||
vr::HmdQuaternion_t qWorldFromDriverRotation;
|
||||
double vecWorldFromDriverTranslation[3];
|
||||
|
||||
vr::HmdQuaternion_t qDriverFromHeadRotation;
|
||||
double vecDriverFromHeadTranslation[3];
|
||||
|
||||
/* State of driver pose, in meters and radians. */
|
||||
/* Position of the driver tracking reference in driver world space
|
||||
* +[0] (x) is right
|
||||
* +[1] (y) is up
|
||||
* -[2] (z) is forward
|
||||
*/
|
||||
double vecPosition[3];
|
||||
|
||||
/* Velocity of the pose in meters/second */
|
||||
double vecVelocity[3];
|
||||
|
||||
/* Acceleration of the pose in meters/second */
|
||||
double vecAcceleration[3];
|
||||
|
||||
/* Orientation of the tracker, represented as a quaternion */
|
||||
vr::HmdQuaternion_t qRotation;
|
||||
|
||||
/* Angular velocity of the pose in axis-angle
|
||||
* representation. The direction is the angle of
|
||||
* rotation and the magnitude is the angle around
|
||||
* that axis in radians/second. */
|
||||
double vecAngularVelocity[3];
|
||||
|
||||
/* Angular acceleration of the pose in axis-angle
|
||||
* representation. The direction is the angle of
|
||||
* rotation and the magnitude is the angle around
|
||||
* that axis in radians/second^2. */
|
||||
double vecAngularAcceleration[3];
|
||||
|
||||
ETrackingResult result;
|
||||
|
||||
bool poseIsValid;
|
||||
bool willDriftInYaw;
|
||||
bool shouldApplyHeadModel;
|
||||
bool deviceIsConnected;
|
||||
};
|
||||
} // end namespace vr
|
||||
|
||||
|
||||
#include "ipc_protocol.h"
|
||||
|
||||
|
||||
namespace vrinputemulator {
|
||||
|
||||
class vrinputemulator_exception : public std::runtime_error {
|
||||
public:
|
||||
const int errorcode = 0;
|
||||
using std::runtime_error::runtime_error;
|
||||
vrinputemulator_exception(const std::string& msg, int code) : std::runtime_error(msg), errorcode(code) {}
|
||||
};
|
||||
|
||||
class vrinputemulator_connectionerror : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidversion : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidid : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_invalidtype : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_notfound : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_alreadyinuse : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
class vrinputemulator_toomanydevices : public vrinputemulator_exception {
|
||||
using vrinputemulator_exception::vrinputemulator_exception;
|
||||
};
|
||||
|
||||
|
||||
struct VirtualDeviceInfo {
|
||||
uint32_t virtualDeviceId;
|
||||
uint32_t openvrDeviceId;
|
||||
VirtualDeviceType deviceType;
|
||||
std::string deviceSerial;
|
||||
};
|
||||
|
||||
|
||||
class VRInputEmulator {
|
||||
public:
|
||||
VRInputEmulator(const std::string& driverQueue = "driver_vrinputemulator.server_queue", const std::string& clientQueue = "driver_vrinputemulator.client_queue.");
|
||||
~VRInputEmulator();
|
||||
|
||||
void connect();
|
||||
bool isConnected() const;
|
||||
void disconnect();
|
||||
|
||||
void ping(bool modal = true, bool enableReply = false);
|
||||
|
||||
void openvrUpdatePose(uint32_t deviceId, const vr::DriverPose_t& pose);
|
||||
void openvrButtonEvent(ButtonEventType eventType, uint32_t deviceId, vr::EVRButtonId buttonId, double timeOffset = 0.0);
|
||||
void openvrAxisEvent(uint32_t deviceId, uint32_t axisId, const vr::VRControllerAxis_t& axisState);
|
||||
void openvrProximitySensorEvent(uint32_t deviceId, bool sensorTriggered);
|
||||
void openvrVendorSpecificEvent(uint32_t deviceId, vr::EVREventType eventType, const vr::VREvent_Data_t& eventData, double timeOffset = 0.0);
|
||||
|
||||
uint32_t getVirtualDeviceCount();
|
||||
VirtualDeviceInfo getVirtualDeviceInfo(uint32_t virtualDeviceId);
|
||||
vr::DriverPose_t getVirtualDevicePose(uint32_t virtualDeviceId);
|
||||
vr::VRControllerState_t getVirtualControllerState(uint32_t virtualDeviceId);
|
||||
uint32_t addVirtualDevice(VirtualDeviceType deviceType, const std::string& deviceSerial, bool softfail = true);
|
||||
void publishVirtualDevice(uint32_t virtualDeviceId, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, int32_t value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, uint64_t value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, float value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, bool value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const std::string& value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const char* value, bool modal = true);
|
||||
void setVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, const vr::HmdMatrix34_t& value, bool modal = true);
|
||||
void removeVirtualDeviceProperty(uint32_t virtualDeviceId, vr::ETrackedDeviceProperty deviceProperty, bool modal = true);
|
||||
void setVirtualDevicePose(uint32_t virtualDeviceId, const vr::DriverPose_t& pose, bool modal = true);
|
||||
void setVirtualControllerState(uint32_t virtualDeviceId, const vr::VRControllerState_t& state, bool modal = true);
|
||||
|
||||
void enableDeviceButtonMapping(uint32_t deviceId, bool enable, bool modal = true);
|
||||
void addDeviceButtonMapping(uint32_t deviceId, vr::EVRButtonId button, vr::EVRButtonId mapped, bool modal = true);
|
||||
void removeDeviceButtonMapping(uint32_t deviceId, vr::EVRButtonId button, bool modal = true);
|
||||
void removeAllDeviceButtonMappings(uint32_t deviceId, bool modal = true);
|
||||
|
||||
void getDeviceOffsets(uint32_t deviceId, DeviceOffsets& data);
|
||||
void enableDeviceOffsets(uint32_t deviceId, bool enable, bool modal = true);
|
||||
void setWorldFromDriverRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setWorldFromDriverTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
void setDriverFromHeadRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setDriverFromHeadTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
void setDriverRotationOffset(uint32_t deviceId, const vr::HmdQuaternion_t& value, bool modal = true);
|
||||
void setDriverTranslationOffset(uint32_t deviceId, const vr::HmdVector3d_t& value, bool modal = true);
|
||||
|
||||
void getDeviceInfo(uint32_t deviceId, DeviceInfo& info);
|
||||
void setDeviceNormalMode(uint32_t deviceId, bool modal = true);
|
||||
void setDeviceFakeDisconnectedMode(uint32_t deviceId, bool modal = true);
|
||||
void setDeviceRedictMode(uint32_t deviceId, uint32_t target, bool modal = true);
|
||||
void setDeviceSwapMode(uint32_t deviceId, uint32_t target, bool modal = true);
|
||||
void setDeviceMotionCompensationMode(uint32_t deviceId, MotionCompensationVelAccMode velAccMode = MotionCompensationVelAccMode::Disabled, bool modal = true);
|
||||
|
||||
void setMotionVelAccCompensationMode(MotionCompensationVelAccMode velAccMode, bool modal = true);
|
||||
void setMotionCompensationKalmanProcessNoise(double variance, bool modal = true);
|
||||
void setMotionCompensationKalmanObservationNoise(double variance, bool modal = true);
|
||||
void setMotionCompensationMovingAverageWindow(unsigned window, bool modal = true);
|
||||
|
||||
void triggerHapticPulse(uint32_t deviceId, uint32_t axisId, uint16_t durationMicroseconds, bool directMode, bool modal = true);
|
||||
|
||||
void setDigitalInputRemapping(uint32_t deviceId, uint32_t buttonId, const DigitalInputRemapping& remapping, bool modal = true);
|
||||
DigitalInputRemapping getDigitalInputRemapping(uint32_t deviceId, uint32_t buttonId);
|
||||
|
||||
void setAnalogInputRemapping(uint32_t deviceId, uint32_t axisId, const AnalogInputRemapping& remapping, bool modal = true);
|
||||
AnalogInputRemapping getAnalogInputRemapping(uint32_t deviceId, uint32_t axisId);
|
||||
|
||||
private:
|
||||
std::recursive_mutex _mutex;
|
||||
uint32_t m_clientId = 0;
|
||||
|
||||
bool _ipcThreadRunning = false;
|
||||
volatile bool _ipcThreadStop = false;
|
||||
std::thread _ipcThread;
|
||||
static void _ipcThreadFunc(VRInputEmulator* _this);
|
||||
|
||||
std::random_device _ipcRandomDevice;
|
||||
std::uniform_int_distribution<uint32_t> _ipcRandomDist;
|
||||
struct _ipcPromiseMapEntry {
|
||||
_ipcPromiseMapEntry() : isValid(false) {}
|
||||
_ipcPromiseMapEntry(std::promise<ipc::Reply>&& _promise, bool isValid = true)
|
||||
: promise(std::move(_promise)), isValid(isValid) {}
|
||||
bool isValid;
|
||||
std::promise<ipc::Reply> promise;
|
||||
};
|
||||
std::map<uint32_t, _ipcPromiseMapEntry> _ipcPromiseMap;
|
||||
std::string _ipcServerQueueName;
|
||||
std::string _ipcClientQueueName;
|
||||
boost::interprocess::message_queue* _ipcServerQueue = nullptr;
|
||||
boost::interprocess::message_queue* _ipcClientQueue = nullptr;
|
||||
|
||||
void _setVirtualDeviceProperty(uint32_t emulatorDeviceId, vr::ETrackedDeviceProperty deviceProperty, std::function<void(ipc::Request&)>, bool modal);
|
||||
};
|
||||
|
||||
} // end namespace vrinputemulator
|
||||
@@ -1,169 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
namespace vrinputemulator {
|
||||
|
||||
static const char* const vrsettings_SectionName = "driver_00vrinputemulator";
|
||||
static const char* const vrsettings_overrideHmdManufacturer_string = "overrideHmdManufacturer";
|
||||
static const char* const vrsettings_overrideHmdModel_string = "overrideHmdModel";
|
||||
static const char* const vrsettings_overrideHmdTrackingSystem_string = "overrideHmdTrackingSystem";
|
||||
static const char* const vrsettings_genericTrackerFakeController_bool = "genericTrackerFakeController";
|
||||
|
||||
enum class VirtualDeviceType : uint32_t {
|
||||
None = 0,
|
||||
TrackedController = 1
|
||||
};
|
||||
|
||||
|
||||
enum class ButtonEventType : uint32_t {
|
||||
None = 0,
|
||||
ButtonPressed = 1,
|
||||
ButtonUnpressed = 2,
|
||||
ButtonTouched = 3,
|
||||
ButtonUntouched = 4,
|
||||
};
|
||||
|
||||
|
||||
enum class DevicePropertyValueType : uint32_t {
|
||||
None = 0,
|
||||
FLOAT = 1,
|
||||
INT32 = 2,
|
||||
UINT64 = 3,
|
||||
BOOL = 4,
|
||||
STRING = 5,
|
||||
MATRIX34 = 20,
|
||||
MATRIX44 = 21,
|
||||
VECTOR3 = 22,
|
||||
VECTOR4 = 23
|
||||
};
|
||||
|
||||
|
||||
struct DeviceOffsets {
|
||||
uint32_t deviceId;
|
||||
bool offsetsEnabled;
|
||||
vr::HmdQuaternion_t worldFromDriverRotationOffset;
|
||||
vr::HmdVector3d_t worldFromDriverTranslationOffset;
|
||||
vr::HmdQuaternion_t driverFromHeadRotationOffset;
|
||||
vr::HmdVector3d_t driverFromHeadTranslationOffset;
|
||||
vr::HmdQuaternion_t deviceRotationOffset;
|
||||
vr::HmdVector3d_t deviceTranslationOffset;
|
||||
};
|
||||
|
||||
|
||||
struct DeviceInfo {
|
||||
uint32_t deviceId;
|
||||
vr::ETrackedDeviceClass deviceClass;
|
||||
int deviceMode;
|
||||
uint32_t refDeviceId;
|
||||
bool offsetsEnabled;
|
||||
bool redirectSuspended;
|
||||
};
|
||||
|
||||
|
||||
enum class MotionCompensationVelAccMode : uint32_t {
|
||||
Disabled = 0,
|
||||
SetZero = 1,
|
||||
SubstractMotionRef = 2,
|
||||
LinearApproximation = 3,
|
||||
KalmanFilter = 4
|
||||
};
|
||||
|
||||
|
||||
enum class DigitalBindingType : uint32_t {
|
||||
NoRemapping = 0,
|
||||
Disabled = 1,
|
||||
OpenVR = 2,
|
||||
Keyboard = 3,
|
||||
SuspendRedirectMode = 4,
|
||||
ToggleTouchpadEmulationFix = 5
|
||||
};
|
||||
|
||||
|
||||
struct DigitalBinding {
|
||||
DigitalBindingType type = DigitalBindingType::NoRemapping;
|
||||
|
||||
union BindingUnion {
|
||||
struct {
|
||||
uint32_t controllerId;
|
||||
uint32_t buttonId;
|
||||
} openvr;
|
||||
|
||||
struct {
|
||||
bool shiftPressed = false;
|
||||
bool ctrlPressed = false;
|
||||
bool altPressed = false;
|
||||
uint32_t keyCode = 0x00;
|
||||
bool sendScanCode = true;
|
||||
} keyboard;
|
||||
|
||||
BindingUnion() {}
|
||||
} data;
|
||||
|
||||
bool toggleEnabled = false;
|
||||
uint32_t toggleDelay = 0;
|
||||
|
||||
bool autoTriggerEnabled = false;
|
||||
uint32_t autoTriggerFrequency = 1;
|
||||
|
||||
DigitalBinding() {}
|
||||
};
|
||||
|
||||
|
||||
struct DigitalInputRemapping {
|
||||
bool valid;
|
||||
DigitalBinding binding;
|
||||
|
||||
bool touchAsClick = false;
|
||||
|
||||
bool longPressEnabled = false;
|
||||
uint32_t longPressThreshold = 1000u;
|
||||
DigitalBinding longPressBinding;
|
||||
bool longPressImmediateRelease = false;
|
||||
|
||||
bool doublePressEnabled = false;
|
||||
uint32_t doublePressThreshold = 300;
|
||||
DigitalBinding doublePressBinding;
|
||||
bool doublePressImmediateRelease = false;
|
||||
|
||||
DigitalInputRemapping(bool valid = false) : valid(valid) {}
|
||||
};
|
||||
|
||||
|
||||
enum class AnalogBindingType : uint32_t {
|
||||
NoRemapping,
|
||||
Disabled,
|
||||
OpenVR
|
||||
};
|
||||
|
||||
struct AnalogBinding {
|
||||
AnalogBindingType type;
|
||||
union BindingUnion {
|
||||
struct {
|
||||
uint32_t controllerId = vr::k_unTrackedDeviceIndexInvalid;
|
||||
uint32_t axisId = 0;
|
||||
} openvr;
|
||||
BindingUnion() {}
|
||||
} data;
|
||||
bool invertXAxis = false;
|
||||
bool invertYAxis = false;
|
||||
bool swapAxes = false;
|
||||
float lowerDeadzone = 0.0;
|
||||
float upperDeadzone = 1.0;
|
||||
unsigned touchpadEmulationMode = 0; // 0 .. Disabled, 1 .. Position Based, 2 .. Position Based (Deferred Zero Updates)
|
||||
bool buttonPressDeadzoneFix = false;
|
||||
|
||||
AnalogBinding(AnalogBindingType type = AnalogBindingType::NoRemapping) : type(type) {}
|
||||
};
|
||||
|
||||
|
||||
struct AnalogInputRemapping {
|
||||
bool valid;
|
||||
AnalogBinding binding;
|
||||
|
||||
AnalogInputRemapping(bool valid = false) : valid(valid) {}
|
||||
};
|
||||
|
||||
|
||||
} // end namespace vrinputemulator
|
||||
File diff suppressed because it is too large.
Load diff
+1168
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user