mirror of
https://github.com/hyblocker/OpenVR-SpaceCalibrator.git
synced 2026-10-06 23:00:20 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6126280c40 | ||
|
|
f8abea143e | ||
|
|
ac16d42d01 | ||
|
|
5c500af0c6 | ||
|
|
c908dff357 | ||
|
|
7217b62e29 | ||
|
|
958136a12c | ||
|
|
92c0e1a0af | ||
|
|
963cd26e90 | ||
|
|
91e0cd15e1 | ||
|
|
e9f9c63768 | ||
|
|
7d4fc8f3d8 | ||
|
|
43ec1657c7 | ||
|
|
77a0375faf |
No files matched your search
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Justin Li
|
||||
|
||||
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.
|
||||
@@ -8,19 +8,13 @@ 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
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,74 +1,38 @@
|
||||
#include "stdafx.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.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
|
||||
{
|
||||
None,
|
||||
Begin,
|
||||
Rotation,
|
||||
Translation,
|
||||
};
|
||||
|
||||
struct CalibrationContext
|
||||
{
|
||||
CalibrationState state = None;
|
||||
int referenceID, targetID;
|
||||
|
||||
vr::HmdQuaternion_t calibratedRotation;
|
||||
vr::HmdVector3d_t calibratedTranslation;
|
||||
std::string calibratedTrackingSystem;
|
||||
|
||||
bool profileLoaded = false, validProfile = false;
|
||||
int ticksSinceScan = 0;
|
||||
};
|
||||
|
||||
|
||||
static vrinputemulator::VRInputEmulator InputEmulator;
|
||||
static CalibrationContext CalCtx;
|
||||
CalibrationContext CalCtx;
|
||||
|
||||
void StartCalibration()
|
||||
{
|
||||
CalCtx.state = Begin;
|
||||
}
|
||||
|
||||
bool InitVR()
|
||||
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);
|
||||
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;
|
||||
throw std::runtime_error("OpenVR error:" + std::string(error));
|
||||
}
|
||||
|
||||
if (!vr::VR_IsInterfaceVersionValid(vr::IVRSystem_Version))
|
||||
{
|
||||
MessageBox(nullptr, L"Outdated IVRSystem_Version", L"Failed to initialize OpenVR", 0);
|
||||
return false;
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSystem_Version");
|
||||
}
|
||||
else if (!vr::VR_IsInterfaceVersionValid(vr::IVRSettings_Version))
|
||||
{
|
||||
MessageBox(nullptr, L"Outdated IVRSettings_Version", L"Failed to initialize OpenVR", 0);
|
||||
return false;
|
||||
throw std::runtime_error("OpenVR error: Outdated IVRSettings_Version");
|
||||
}
|
||||
|
||||
InputEmulator.connect();
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Pose
|
||||
@@ -103,6 +67,22 @@ struct DSample
|
||||
Eigen::Vector3d ref, target;
|
||||
};
|
||||
|
||||
bool StartsWith(const std::string &str, const std::string &prefix)
|
||||
{
|
||||
if (str.length() < prefix.length())
|
||||
return false;
|
||||
|
||||
return str.compare(0, prefix.length(), prefix) == 0;
|
||||
}
|
||||
|
||||
bool EndsWith(const std::string &str, const std::string &suffix)
|
||||
{
|
||||
if (str.length() < suffix.length())
|
||||
return false;
|
||||
|
||||
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
}
|
||||
|
||||
Eigen::Vector3d AxisFromRotationMatrix3(Eigen::Matrix3d rot)
|
||||
{
|
||||
return Eigen::Vector3d(rot(2,1) - rot(1,2), rot(0,2) - rot(2,0), rot(1,0) - rot(0,1));
|
||||
@@ -135,41 +115,30 @@ DSample DeltaRotationSamples(Sample s1, Sample s2)
|
||||
return ds;
|
||||
}
|
||||
|
||||
bool StartsWith(const std::string &str, const std::string &prefix)
|
||||
{
|
||||
if (str.length() < prefix.length())
|
||||
return false;
|
||||
|
||||
return str.compare(0, prefix.length(), prefix) == 0;
|
||||
}
|
||||
|
||||
bool EndsWith(const std::string &str, const std::string &suffix)
|
||||
{
|
||||
if (str.length() < suffix.length())
|
||||
return false;
|
||||
|
||||
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
}
|
||||
|
||||
Eigen::Matrix3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
Eigen::Vector3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
{
|
||||
std::vector<DSample> deltas;
|
||||
|
||||
for (size_t i = 0; i < samples.size(); i++) {
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
for (size_t i = 0; i < samples.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < i; j++)
|
||||
{
|
||||
auto delta = DeltaRotationSamples(samples[i], samples[j]);
|
||||
if (delta.valid)
|
||||
deltas.push_back(delta);
|
||||
}
|
||||
}
|
||||
printf("\ngot %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
|
||||
|
||||
Eigen::MatrixXd refPoints(deltas.size(), 3), targetPoints(deltas.size(), 3);
|
||||
Eigen::Vector3d refCentroid(0,0,0), targetCentroid(0,0,0);
|
||||
|
||||
for (size_t i = 0; i < deltas.size(); i++) {
|
||||
for (size_t i = 0; i < deltas.size(); i++)
|
||||
{
|
||||
refPoints.row(i) = deltas[i].ref;
|
||||
refCentroid += deltas[i].ref;
|
||||
|
||||
@@ -180,7 +149,8 @@ Eigen::Matrix3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
refCentroid /= (double) deltas.size();
|
||||
targetCentroid /= (double) deltas.size();
|
||||
|
||||
for (size_t i = 0; i < deltas.size(); i++) {
|
||||
for (size_t i = 0; i < deltas.size(); i++)
|
||||
{
|
||||
refPoints.row(i) -= refCentroid;
|
||||
targetPoints.row(i) -= targetCentroid;
|
||||
}
|
||||
@@ -191,7 +161,8 @@ Eigen::Matrix3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
auto svd = bdcsvd.compute(crossCV, Eigen::ComputeThinU | Eigen::ComputeThinV);
|
||||
|
||||
Eigen::Matrix3d i = Eigen::Matrix3d::Identity();
|
||||
if ((svd.matrixU() * svd.matrixV().transpose()).determinant() < 0) {
|
||||
if ((svd.matrixU() * svd.matrixV().transpose()).determinant() < 0)
|
||||
{
|
||||
i(2,2) = -1;
|
||||
}
|
||||
|
||||
@@ -199,16 +170,20 @@ Eigen::Matrix3d CalibrateRotation(const std::vector<Sample> &samples)
|
||||
rot.transposeInPlace();
|
||||
|
||||
Eigen::Vector3d euler = rot.eulerAngles(2, 1, 0) * 180.0 / EIGEN_PI;
|
||||
printf("rotation yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[0], euler[2]);
|
||||
return rot;
|
||||
|
||||
snprintf(buf, sizeof buf, "Calibrated rotation: yaw=%.2f pitch=%.2f roll=%.2f\n", euler[1], euler[2], euler[0]);
|
||||
CalCtx.Message(buf);
|
||||
return euler;
|
||||
}
|
||||
|
||||
Eigen::Vector3d CalibrateTranslation(const std::vector<Sample> &samples)
|
||||
{
|
||||
std::vector<std::pair<Eigen::Vector3d, Eigen::Matrix3d>> deltas;
|
||||
|
||||
for (size_t i = 0; i < samples.size(); i++) {
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
for (size_t i = 0; i < samples.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < i; j++)
|
||||
{
|
||||
auto QAi = samples[i].ref.rot.transpose();
|
||||
auto QAj = samples[j].ref.rot.transpose();
|
||||
auto dQA = QAj - QAi;
|
||||
@@ -226,35 +201,46 @@ Eigen::Vector3d CalibrateTranslation(const std::vector<Sample> &samples)
|
||||
Eigen::VectorXd constants(deltas.size() * 3);
|
||||
Eigen::MatrixXd coefficients(deltas.size() * 3, 3);
|
||||
|
||||
for (size_t i = 0; i < deltas.size(); i++) {
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
for (size_t i = 0; i < deltas.size(); i++)
|
||||
{
|
||||
for (int axis = 0; axis < 3; axis++)
|
||||
{
|
||||
constants(i * 3 + axis) = deltas[i].first(axis);
|
||||
coefficients.row(i * 3 + axis) = deltas[i].second.row(axis);
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::Vector3d trans = coefficients.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(constants);
|
||||
trans(0) *= -1;
|
||||
auto transcm = trans * 100.0;
|
||||
|
||||
printf("\ntranslation x=%.2f y=%.2f z=%.2f\n", transcm[0], transcm[1], transcm[2]);
|
||||
return trans;
|
||||
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::TrackingUniverseStanding, 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();
|
||||
}
|
||||
|
||||
@@ -264,130 +250,78 @@ Sample CollectSample(const CalibrationContext &ctx)
|
||||
);
|
||||
}
|
||||
|
||||
bool PickDevices(CalibrationContext &ctx)
|
||||
vr::HmdQuaternion_t VRRotationQuat(Eigen::Vector3d eulerdeg)
|
||||
{
|
||||
auto euler = eulerdeg * EIGEN_PI / 180.0;
|
||||
|
||||
Eigen::Quaterniond rotQuat =
|
||||
Eigen::AngleAxisd(euler(0), Eigen::Vector3d::UnitZ()) *
|
||||
Eigen::AngleAxisd(euler(1), Eigen::Vector3d::UnitY()) *
|
||||
Eigen::AngleAxisd(euler(2), Eigen::Vector3d::UnitX());
|
||||
|
||||
vr::HmdQuaternion_t vrRotQuat;
|
||||
vrRotQuat.x = rotQuat.coeffs()[0];
|
||||
vrRotQuat.y = rotQuat.coeffs()[1];
|
||||
vrRotQuat.z = rotQuat.coeffs()[2];
|
||||
vrRotQuat.w = rotQuat.coeffs()[3];
|
||||
return vrRotQuat;
|
||||
}
|
||||
|
||||
vr::HmdVector3d_t VRTranslationVec(Eigen::Vector3d transcm)
|
||||
{
|
||||
auto trans = transcm * 0.01;
|
||||
vr::HmdVector3d_t vrTrans;
|
||||
vrTrans.v[0] = trans[0];
|
||||
vrTrans.v[1] = trans[1];
|
||||
vrTrans.v[2] = trans[2];
|
||||
return vrTrans;
|
||||
}
|
||||
|
||||
void ScanAndApplyProfile(CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
|
||||
vr::TrackedDevicePose_t devicePoses[vr::k_unMaxTrackedDeviceCount];
|
||||
vr::VRSystem()->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 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)
|
||||
/*if (deviceClass == vr::TrackedDeviceClass_HMD) // for debugging unexpected universe switches
|
||||
{
|
||||
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.w
|
||||
>> ctx.calibratedRotation.x
|
||||
>> ctx.calibratedRotation.y
|
||||
>> ctx.calibratedRotation.z
|
||||
>> ctx.calibratedTranslation.v[0]
|
||||
>> ctx.calibratedTranslation.v[1]
|
||||
>> ctx.calibratedTranslation.v[2];
|
||||
|
||||
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.w << " "
|
||||
<< ctx.calibratedRotation.x << " "
|
||||
<< ctx.calibratedRotation.y << " "
|
||||
<< ctx.calibratedRotation.z << std::endl
|
||||
<< ctx.calibratedTranslation.v[0] << " "
|
||||
<< ctx.calibratedTranslation.v[1] << " "
|
||||
<< ctx.calibratedTranslation.v[2] << std::endl;
|
||||
|
||||
ctx.profileLoaded = true;
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
void ScanAndApplyProfile(const CalibrationContext &ctx)
|
||||
{
|
||||
char buffer[vr::k_unMaxPropertyStringSize];
|
||||
|
||||
for (uint32_t id = 0; id < vr::k_unMaxTrackedDeviceCount; ++id)
|
||||
{
|
||||
auto deviceClass = vr::VRSystem()->GetTrackedDeviceClass(id);
|
||||
if (deviceClass == vr::TrackedDeviceClass_Invalid)
|
||||
auto universeId = vr::VRSystem()->GetUint64TrackedDeviceProperty(id, vr::Prop_CurrentUniverseId_Uint64, &err);
|
||||
printf("uid %d err %d\n", universeId, err);
|
||||
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)
|
||||
{
|
||||
std::string trackingSystem(buffer);
|
||||
if (err != vr::TrackedProp_Success)
|
||||
continue;
|
||||
|
||||
if (trackingSystem == ctx.calibratedTrackingSystem)
|
||||
{
|
||||
//printf("setting calibration for %d (%s)\n", id, buffer);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(id, ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(id, ctx.calibratedTranslation);
|
||||
InputEmulator.enableDeviceOffsets(id, true);
|
||||
}
|
||||
std::string trackingSystem(buffer);
|
||||
|
||||
if (trackingSystem != ctx.targetTrackingSystem)
|
||||
continue;
|
||||
|
||||
if (deviceClass == vr::TrackedDeviceClass_TrackingReference || deviceClass == vr::TrackedDeviceClass_HMD)
|
||||
{
|
||||
// TODO(pushrax): detect zero reference switches and adjust calibration automatically
|
||||
//auto p = ctx.devicePoses[id].mDeviceToAbsoluteTracking.m;
|
||||
//printf("REF %d: %f %f %f\n", id, p[0][3], p[1][3], p[2][3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -405,42 +339,87 @@ void ResetAndDisableOffsets(uint32_t id)
|
||||
InputEmulator.enableDeviceOffsets(id, false);
|
||||
}
|
||||
|
||||
void CalibrationTick()
|
||||
void StartCalibration()
|
||||
{
|
||||
CalCtx.state = CalibrationState::Begin;
|
||||
CalCtx.wantedUpdateInterval = 0.0;
|
||||
CalCtx.messages = "";
|
||||
}
|
||||
|
||||
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 (!ctx.validProfile)
|
||||
return;
|
||||
|
||||
if ((time - ctx.timeLastScan) >= 2.5)
|
||||
{
|
||||
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.0;
|
||||
|
||||
if (!ctx.validProfile)
|
||||
return;
|
||||
|
||||
ScanAndApplyProfile(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx.state == CalibrationState::Begin)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
if (ctx.referenceID == -1)
|
||||
{
|
||||
ResetAndDisableOffsets(ctx.targetID);
|
||||
ctx.state = Rotation;
|
||||
printf("starting calibration, referenceID=%d targetID=%d\n", ctx.referenceID, ctx.targetID);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -449,7 +428,7 @@ void CalibrationTick()
|
||||
{
|
||||
return;
|
||||
}
|
||||
printf(".");
|
||||
CalCtx.Message(".");
|
||||
|
||||
const int totalSamples = 100;
|
||||
static std::vector<Sample> samples;
|
||||
@@ -457,41 +436,30 @@ void CalibrationTick()
|
||||
|
||||
if (samples.size() == totalSamples)
|
||||
{
|
||||
if (ctx.state == Rotation)
|
||||
CalCtx.Message("\n");
|
||||
if (ctx.state == CalibrationState::Rotation)
|
||||
{
|
||||
auto rot = CalibrateRotation(samples);
|
||||
Eigen::Quaterniond rotQuat(rot);
|
||||
|
||||
vr::HmdQuaternion_t vrRotQuat;
|
||||
vrRotQuat.x = rotQuat.coeffs()[0];
|
||||
vrRotQuat.y = rotQuat.coeffs()[1];
|
||||
vrRotQuat.z = rotQuat.coeffs()[2];
|
||||
vrRotQuat.w = rotQuat.coeffs()[3];
|
||||
ctx.calibratedRotation = CalibrateRotation(samples);
|
||||
|
||||
auto vrRotQuat = VRRotationQuat(ctx.calibratedRotation);
|
||||
InputEmulator.setWorldFromDriverRotationOffset(ctx.targetID, vrRotQuat);
|
||||
InputEmulator.enableDeviceOffsets(ctx.targetID, true);
|
||||
|
||||
ctx.calibratedRotation = vrRotQuat;
|
||||
ctx.state = Translation;
|
||||
ctx.state = CalibrationState::Translation;
|
||||
}
|
||||
else if (ctx.state == Translation)
|
||||
else if (ctx.state == CalibrationState::Translation)
|
||||
{
|
||||
auto trans = CalibrateTranslation(samples);
|
||||
|
||||
vr::HmdVector3d_t vrTrans;
|
||||
vrTrans.v[0] = trans[0];
|
||||
vrTrans.v[1] = trans[1];
|
||||
vrTrans.v[2] = trans[2];
|
||||
ctx.calibratedTranslation = CalibrateTranslation(samples);
|
||||
|
||||
auto vrTrans = VRTranslationVec(ctx.calibratedTranslation);
|
||||
InputEmulator.setWorldFromDriverTranslationOffset(ctx.targetID, vrTrans);
|
||||
|
||||
ctx.calibratedTranslation = vrTrans;
|
||||
ctx.state = None;
|
||||
|
||||
SaveProfile(ctx);
|
||||
printf("finished calibration, profile saved\n");
|
||||
CalCtx.Message("Finished calibration, profile saved\n");
|
||||
|
||||
ctx.state = CalibrationState::None;
|
||||
}
|
||||
|
||||
samples.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
bool InitVR();
|
||||
void StartCalibration();
|
||||
void CalibrationTick();
|
||||
#include <Eigen/Core>
|
||||
#include <openvr.h>
|
||||
|
||||
enum class CalibrationState
|
||||
{
|
||||
None,
|
||||
Begin,
|
||||
Rotation,
|
||||
Translation,
|
||||
Editing,
|
||||
};
|
||||
|
||||
struct CalibrationContext
|
||||
{
|
||||
CalibrationState state = CalibrationState::None;
|
||||
int 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];
|
||||
|
||||
std::string messages;
|
||||
|
||||
void Message(const std::string &msg)
|
||||
{
|
||||
messages += msg;
|
||||
std::cerr << msg;
|
||||
}
|
||||
};
|
||||
|
||||
extern CalibrationContext CalCtx;
|
||||
|
||||
void InitVR();
|
||||
void CalibrationTick(double time);
|
||||
void StartCalibration();
|
||||
@@ -0,0 +1,113 @@
|
||||
#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);
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ifstream file("openvr_space_calibration.json");
|
||||
ctx.validProfile = false;
|
||||
|
||||
if (!file.good())
|
||||
{
|
||||
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>();
|
||||
|
||||
ctx.validProfile = true;
|
||||
}
|
||||
|
||||
void SaveProfile(CalibrationContext &ctx)
|
||||
{
|
||||
std::ofstream file("openvr_space_calibration.json");
|
||||
|
||||
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));
|
||||
|
||||
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");
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Calibration.h"
|
||||
|
||||
void LoadProfile(CalibrationContext &ctx);
|
||||
void SaveProfile(CalibrationContext &ctx);
|
||||
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];
|
||||
@@ -1,21 +1,19 @@
|
||||
#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>
|
||||
|
||||
#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);
|
||||
|
||||
void CreateConsole()
|
||||
{
|
||||
static bool created = false;
|
||||
@@ -30,112 +28,104 @@ void CreateConsole()
|
||||
}
|
||||
}
|
||||
|
||||
void GLFWErrorCallback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
GLFWwindow *glfwWindow = nullptr;
|
||||
|
||||
void CreateGLFWWindow()
|
||||
{
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
glfwWindow = glfwCreateWindow(1280, 800, "OpenVR-SpaceCalibrator", NULL, NULL);
|
||||
if (!glfwWindow)
|
||||
throw std::runtime_error("Failed to create window");
|
||||
|
||||
glfwMakeContextCurrent(glfwWindow);
|
||||
glfwSwapInterval(1);
|
||||
gl3wInit();
|
||||
|
||||
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 150");
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
}
|
||||
|
||||
void RunLoop()
|
||||
{
|
||||
while (!glfwWindowShouldClose(glfwWindow))
|
||||
{
|
||||
double time = glfwGetTime();
|
||||
CalibrationTick(time);
|
||||
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(glfwWindow, &width, &height);
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
ImGui_ImplGlfw_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
BuildMainWindow();
|
||||
|
||||
ImGui::Render();
|
||||
|
||||
glViewport(0, 0, width, height);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
glfwSwapBuffers(glfwWindow);
|
||||
glfwWaitEventsTimeout(CalCtx.wantedUpdateInterval);
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(hPrevInstance);
|
||||
UNREFERENCED_PARAMETER(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;
|
||||
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
|
||||
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));
|
||||
|
||||
return RegisterClassExW(&wcex);
|
||||
}
|
||||
|
||||
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);
|
||||
try {
|
||||
InitVR();
|
||||
CreateGLFWWindow();
|
||||
LoadProfile(CalCtx);
|
||||
RunLoop();
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "resource.h"
|
||||
@@ -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\glfw\include;..\lib\openvr;..\lib\boost_1_63_0;..\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\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>
|
||||
</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,15 +73,15 @@
|
||||
<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\boost_1_63_0;..\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\boost_1_63_0\lib64-msvc-14.0;..\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>
|
||||
@@ -161,35 +92,54 @@
|
||||
<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="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="UserInterface.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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="..\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>
|
||||
<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="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,6 +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>
|
||||
<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>
|
||||
<Text Include="ReadMe.txt" />
|
||||
@@ -24,12 +30,6 @@
|
||||
<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>
|
||||
@@ -42,6 +42,15 @@
|
||||
<ClInclude Include="..\lib\lib_vrinputemulator\vrinputemulator_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EmbeddedFiles.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UserInterface.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Configuration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
@@ -56,11 +65,33 @@
|
||||
<ClCompile Include="..\lib\lib_vrinputemulator\vrinputemulator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="small.ico">
|
||||
@@ -70,4 +101,9 @@
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="OpenVR-SpaceCalibrator.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,410 @@
|
||||
#include "stdafx.h"
|
||||
#include "UserInterface.h"
|
||||
#include "Calibration.h"
|
||||
#include "Configuration.h"
|
||||
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
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()
|
||||
{
|
||||
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();
|
||||
float scale = 1.0f;
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
width -= style.FramePadding.x * 2.0f;
|
||||
scale = 2.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Start New Calibration", ImVec2(width * scale, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
ImGui::OpenPopup("Calibration Progress");
|
||||
StartCalibration();
|
||||
}
|
||||
|
||||
if (CalCtx.validProfile)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Edit Calibration", ImVec2(width / 3.0f, ImGui::GetTextLineHeight() * 2)))
|
||||
{
|
||||
CalCtx.state = CalibrationState::Editing;
|
||||
}
|
||||
}
|
||||
}
|
||||
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(ImGui::GetWindowWidth() - 60.0f, ImGui::GetWindowHeight() - ImGui::GetItemsLineHeightWithSpacing()));
|
||||
ImGui::BeginChild("version stuff", ImVec2(60.0f, ImGui::GetItemsLineHeightWithSpacing() * 2), false);
|
||||
ImGui::Text("v0.5");
|
||||
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();
|
||||
@@ -0,0 +1,52 @@
|
||||
# OpenVR-SpaceCalibrator
|
||||
|
||||
Use VR devices from one company with any other.
|
||||
|
||||
This is **beta software** and may not work for you. A quick video walkthrough of the calibration process is available at https://www.youtube.com/watch?v=W3TnQd9JMl4
|
||||
|
||||
## Usage
|
||||
|
||||
### Calibration
|
||||
|
||||
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.
|
||||
4. Hold the left Touch controller and your Vive device in your left hand securely, like they're glued together.
|
||||
5. Click "Start Calibration"
|
||||
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.
|
||||
|
||||
### Setting up SteamVR
|
||||
|
||||
Every hardware designer with their own tracking system needs to make a "driver"
|
||||
so SteamVR can see their tracking data. SteamVR by default will load only one driver at a time,
|
||||
but we can tell it to load all of them by editing the vrsettings config file.
|
||||
|
||||
Open `Steam\steamapps\common\SteamVR\resources\settings\default.vrsettings` in a text editor,
|
||||
look for the line that has `"activateMultipleDrivers": false` and change the `false` to `true`.
|
||||
In some guides online you may also see references to `requireHmd`, this does _not_ need to be changed
|
||||
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.
|
||||
|
||||
|
||||
## The math
|
||||
|
||||
See [math.pdf](https://github.com/pushrax/OpenVR-SpaceCalibrator/blob/master/math.pdf) for details.
|
||||
If you have some ideas for how to improve the calibration process, let me know!
|
||||
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);
|
||||
}
|
||||
*/
|
||||
+13950
File diff suppressed because it is too large.
Load diff
+1924
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,290 @@
|
||||
// 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 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);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Update mouse position
|
||||
const ImVec2 mouse_pos_backup = io.MousePos;
|
||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||
if (glfwGetWindowAttrib(g_Window, GLFW_FOCUSED))
|
||||
{
|
||||
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()
|
||||
|
||||
// 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);
|
||||
|
||||
// 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,32 @@
|
||||
// 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);
|
||||
@@ -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"
|
||||
"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
+1168
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user