diff --git a/src/bezier.h b/src/bezier.h index bd0fc6a..ae34c46 100644 --- a/src/bezier.h +++ b/src/bezier.h @@ -1,16 +1,16 @@ #pragma once +// link: https://www.codeproject.com/Articles/25237/Bezier-Curves-Made-Simple class BezierCurve { static double FactorialLookup[33]; + public: // just check if n is appropriate, then return the result static double factorial(int n) { -// if (n < 0) { throw new Exception("n is less than 0"); } -// if (n > 32) { throw new Exception("n is greater than 32"); } - return FactorialLookup[n]; /* returns the value n! as a SUMORealing point number */ + return FactorialLookup[n]; } static double Ni(int n, int i) @@ -27,10 +27,8 @@ public: static double Bernstein(int n, int i, double t) { double basis; - double ti; /* t^i */ - double tni; /* (1 - t)^i */ - - /* Prevent problems with pow */ + double ti; + double tni; if (t == 0.0 && i == 0) ti = 1.0; @@ -49,9 +47,6 @@ public: static glm::vec2 Bezier2D(const std::vector& b, double t) { -// if ((1.0 - t) < 5e-6) -// t = 1.0; - double px = 0.0; double py = 0.0; const int npts = (int)b.size(); diff --git a/src/canvas.cpp b/src/canvas.cpp index b4dc960..e13e095 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -424,8 +424,26 @@ void Canvas::stroke_draw() auto bb_sz = bb_max - bb_min; if (m_brush.m_tip_mix > 0.f) + { stroke_draw_mix(bb_min, bb_sz); + glViewport(0, 0, m_width, m_height); + + glActiveTexture(GL_TEXTURE0); + tex.bind(); + m_sampler_brush.bind(0); + m_sampler_bg.bind(1); + m_sampler_stencil.bind(2); + m_sampler.bind(3); + //m_sampler_linear.bind(5); + + glActiveTexture(GL_TEXTURE2); + stencil.bind(); + glActiveTexture(GL_TEXTURE3); + m_mixer.bindTexture(); + glDisable(GL_BLEND); + } + for (int i = 0; i < 6; i++) { // check if plane is even visible @@ -529,7 +547,7 @@ void Canvas::stroke_draw() glm::max(zw(m_dirty_box[i]), (glm::vec2)(tex_pos + tex_sz)) ); - //ShaderManager::use(kShader::Stroke); + ShaderManager::use(kShader::Stroke); ShaderManager::u_mat4(kShaderUniform::MVP, ortho_proj); ShaderManager::u_vec4(kShaderUniform::Col, glm::vec4(s.col, m_brush.m_tip_color.a)); ShaderManager::u_float(kShaderUniform::Alpha, s.flow); diff --git a/src/hmd.cpp b/src/hmd.cpp index 46e6be3..cecb7d9 100644 --- a/src/hmd.cpp +++ b/src/hmd.cpp @@ -3,61 +3,28 @@ #include "log.h" #include -Vive::Vive() -{ - for (int i = 0; i < 2; i++) - controllers[i].active = true; -} - -std::string Vive::ReadPropString(vr::TrackedDeviceIndex_t nDevice, vr::ETrackedDeviceProperty p) -{ - size_t len = hmd->GetStringTrackedDeviceProperty(nDevice, p, nullptr, 0); - std::string str(len, '\0'); - hmd->GetStringTrackedDeviceProperty(nDevice, p, (char*)str.data(), len); - return str; -} - bool Vive::Initialize() { vr::EVRInitError error; - hmd = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Scene); + m_hmd = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Scene); if (error != vr::EVRInitError::VRInitError_None) return false; - comp = vr::VRCompositor(); - if (!comp) + + if (!(m_comp = vr::VRCompositor())) return false; - settings = vr::VRSettings(); + m_settings = vr::VRSettings(); - hmd->GetRecommendedRenderTargetSize(&eyeWidth, &eyeHeight); - LOG("Eye target resolution: %dx%d\n", eyeWidth, eyeHeight); + m_hmd->GetRecommendedRenderTargetSize(&m_eye_width, &m_eye_height); for (int eye = 0; eye < 2; ++eye) { - eyes[eye].create(eyeWidth, eyeHeight); - eyes[eye].bindFramebuffer(); - eyes[eye].clear({ 1, 0, 0, 1 }); - eyes[eye].unbindFramebuffer(); + m_eyes[eye].create(m_eye_width, m_eye_height); + m_eyes[eye].bindFramebuffer(); + m_eyes[eye].clear({ 1, 0, 0, 1 }); + m_eyes[eye].unbindFramebuffer(); } - int attempts = 50; - do - { - int nc = 0; - for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice) - { - if (hmd->GetTrackedDeviceClass(nDevice) == vr::TrackedDeviceClass_HMD) - { - dev_tracksys = ReadPropString(nDevice, vr::Prop_TrackingSystemName_String); - dev_serial = ReadPropString(nDevice, vr::Prop_SerialNumber_String); - dev_model = ReadPropString(nDevice, vr::Prop_ModelNumber_String); - dev_manufacturer = ReadPropString(nDevice, vr::Prop_ManufacturerName_String); - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - attempts--; - } while (attempts > 0 && dev_serial.empty()); - - vr::CVRSettingHelper s(settings); + vr::CVRSettingHelper s(m_settings); float timeout = s.GetFloat(vr::k_pch_Power_Section, vr::k_pch_Power_TurnOffScreensTimeout_Float); s.SetFloat(vr::k_pch_Power_Section, vr::k_pch_Power_TurnOffScreensTimeout_Float, 0.5); @@ -69,194 +36,92 @@ void Vive::Terminate() vr::VR_Shutdown(); } -void Vive::ResetYaw() -{ - yaw_offset = euler.y; -} - void Vive::Update() { - if (!(hmd && comp)) + if (!(m_hmd && m_comp)) return; vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount]; - comp->WaitGetPoses(poses, vr::k_unMaxTrackedDeviceCount, NULL, 0); - auto& hmdPose = poses[vr::k_unTrackedDeviceIndex_Hmd]; + m_comp->WaitGetPoses(poses, vr::k_unMaxTrackedDeviceCount, NULL, 0); + auto& current_pose = poses[vr::k_unTrackedDeviceIndex_Hmd]; for (int eye = 0; eye < 2; ++eye) { // Get view and projection matrices - vr::HmdMatrix44_t p = hmd->GetProjectionMatrix((vr::EVREye)eye, 0.2f, 1000.f); - float eyeProj[4][4] = { + vr::HmdMatrix44_t p = m_hmd->GetProjectionMatrix((vr::EVREye)eye, 0.2f, 1000.f); + float data_eye_proj[16] = { p.m[0][0], p.m[1][0], p.m[2][0], p.m[3][0], p.m[0][1], p.m[1][1], p.m[2][1], p.m[3][1], p.m[0][2], p.m[1][2], p.m[2][2], p.m[3][2], p.m[0][3], p.m[1][3], p.m[2][3], p.m[3][3], }; - vr::HmdMatrix34_t e = hmd->GetEyeToHeadTransform((vr::EVREye)eye); - float eyePose[4][4] = { + vr::HmdMatrix34_t e = m_hmd->GetEyeToHeadTransform((vr::EVREye)eye); + float data_eye_pose[16] = { e.m[0][0], e.m[1][0], e.m[2][0], 0, e.m[0][1], e.m[1][1], e.m[2][1], 0, e.m[0][2], e.m[1][2], e.m[2][2], 0, e.m[0][3], e.m[1][3], e.m[2][3], 1, }; - vr::HmdMatrix34_t h = hmdPose.mDeviceToAbsoluteTracking; - float hmdPose[4][4] = { + vr::HmdMatrix34_t h = current_pose.mDeviceToAbsoluteTracking; + float data_hmd_pose[16] = { h.m[0][0], h.m[1][0], h.m[2][0], 0, h.m[0][1], h.m[1][1], h.m[2][1], 0, h.m[0][2], h.m[1][2], h.m[2][2], 0, - 0, 0, 0, 1, + 0, 0, 0, 1, // rotation only //h.m[0][3], h.m[1][3], h.m[2][3], 1, }; - auto mat_proj = glm::make_mat4((float*)eyeProj); - auto mat_pose = glm::inverse(glm::make_mat4((float*)hmdPose)); - auto mat_eye = glm::inverse(glm::make_mat4((float*)eyePose)); - auto hmd_position = glm::vec3(h.m[0][3], h.m[1][3], h.m[2][3]); + auto mat_proj = glm::make_mat4(data_eye_proj); + auto mat_pose = glm::inverse(glm::make_mat4(data_hmd_pose)); + auto mat_eye = glm::inverse(glm::make_mat4(data_eye_pose)); - proj[eye] = mat_proj; - view[eye] = mat_eye * mat_pose; - pose = mat_pose; + m_proj[eye] = mat_proj; + m_view[eye] = mat_eye * mat_pose; + m_pose = mat_pose; - for (auto& c : controllers) - c.valid = false; - for (auto& c : trackers) - c.valid = false; - - int nc = 0; - int nt = 0; - for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice) + for (int id = 0; id < vr::k_unMaxTrackedDeviceCount; id++) { - if (poses[nDevice].bPoseIsValid) + switch (m_hmd->GetTrackedDeviceClass(id)) { - vr::HmdMatrix34_t p = poses[nDevice].mDeviceToAbsoluteTracking; - float mat[4][4] = { - p.m[0][0], p.m[1][0], p.m[2][0], 0, - p.m[0][1], p.m[1][1], p.m[2][1], 0, - p.m[0][2], p.m[1][2], p.m[2][2], 0, - p.m[0][3], p.m[1][3], p.m[2][3], 1, - }; - switch (hmd->GetTrackedDeviceClass(nDevice)) - { - case vr::TrackedDeviceClass_Controller: - { - vr::EVRInitError error; - vr::ETrackedControllerRole controllerRole = (vr::ETrackedControllerRole) - hmd->GetInt32TrackedDeviceProperty(nDevice, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32); - - auto& c = controllers[nc]; - c.index = nc; - c.active = true; - c.valid = true; - hmd->GetControllerState(nDevice, &c.state, sizeof(vr::VRControllerState_t)); - auto c_mat = glm::translate(-hmd_position) * glm::make_mat4((float*)mat); - c.update(c_mat); - c.buttons_bits = c.state.ulButtonPressed; - c.role = controllerRole; - for (int axi = 0; axi < 5; axi++) - { - c.axis[axi].x = c.state.rAxis[axi].x; - c.axis[axi].y = c.state.rAxis[axi].y; - - for (auto b : { Controller::ButtonAxis::Trigger }) - { - if (axi != (uint8_t)b) - continue; - if (glm::compMax(glm::abs(c.axis[axi])) > 0.f && !c.buttons_axis[(uint8_t)b]) - { - c.buttons_axis[(uint8_t)b] = true; - if (on_button_axis) - on_button_axis(c, b, Controller::Action::Press); - } - if (glm::compMax(glm::abs(c.axis[axi])) == 0.f && c.buttons_axis[(uint64_t)b]) - { - c.buttons_axis[(uint8_t)b] = false; - if (on_button_axis) - on_button_axis(c, b, Controller::Action::Release); - } - } - } - - auto btn = c.state.ulButtonPressed; - for (auto b : { Controller::Button::Trigger, Controller::Button::Grip }) - { - if ((btn & (uint64_t)b) != 0 && !c.buttons[(uint64_t)b]) - { - c.buttons[(uint64_t)b] = true; - if (on_button) - on_button(c, b, Controller::Action::Press); - } - if ((btn & (uint64_t)b) == 0 && c.buttons[(uint64_t)b]) - { - c.buttons[(uint64_t)b] = false; - if (on_button) - on_button(c, b, Controller::Action::Release); - } - } - nc++; - } - break; case vr::TrackedDeviceClass_HMD: - { - auto level = hmd->GetTrackedDeviceActivityLevel(nDevice); - active = (level == vr::k_EDeviceActivityLevel_UserInteraction); - } - break; - case vr::TrackedDeviceClass_Invalid: - break; - case vr::TrackedDeviceClass_GenericTracker: - { - auto& c = trackers[nt]; - c.index = nt; - c.active = true; - c.valid = true; - c.update(glm::make_mat4((float*)mat)); - } - break; - case vr::TrackedDeviceClass_TrackingReference: + m_active = (m_hmd->GetTrackedDeviceActivityLevel(id) == vr::k_EDeviceActivityLevel_UserInteraction); break; default: break; - } } } - - if (nc > 1 && swap_controllers) - { - std::swap(controllers[0], controllers[1]); - } } } void Vive::Draw() { - if (!(hmd && comp && comp_attempts < 10)) + if (!Valid()) return; for (int eye = 0; eye < 2; ++eye) { - eyes[eye].bindFramebuffer(); - eyes[eye].clear(background); - glViewport(0, 0, eyes[eye].getWidth(), eyes[eye].getHeight()); + m_eyes[eye].bindFramebuffer(); + m_eyes[eye].clear(); + glViewport(0, 0, m_eyes[eye].getWidth(), m_eyes[eye].getHeight()); if (on_draw) - on_draw(proj[eye], view[eye], pose); + on_draw(m_proj[eye], m_view[eye], m_pose); - eyes[eye].unbindFramebuffer(); + m_eyes[eye].unbindFramebuffer(); } - vr::Texture_t eyeTexture0 = { (void*)eyes[0].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear }; - if (auto err = comp->Submit(vr::EVREye::Eye_Left, &eyeTexture0) != vr::EVRCompositorError::VRCompositorError_None) + vr::Texture_t eyeTexture0 = { (void*)m_eyes[0].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear }; + if (auto err = m_comp->Submit(vr::EVREye::Eye_Left, &eyeTexture0) != vr::EVRCompositorError::VRCompositorError_None) { LOG("Compositor error %d", err); comp_attempts++; return; } - vr::Texture_t eyeTexture1 = { (void*)eyes[1].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear }; - if (auto err = comp->Submit(vr::EVREye::Eye_Right, &eyeTexture1) != vr::EVRCompositorError::VRCompositorError_None) + vr::Texture_t eyeTexture1 = { (void*)m_eyes[1].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear }; + if (auto err = m_comp->Submit(vr::EVREye::Eye_Right, &eyeTexture1) != vr::EVRCompositorError::VRCompositorError_None) { LOG("Compositor error %d", err); comp_attempts++; @@ -265,11 +130,9 @@ void Vive::Draw() comp_attempts = 0; glFlush(); - // glFinish(); - // glBindTexture(GL_TEXTURE_2D, 0); } bool Vive::Valid() { - return comp && comp_attempts < 10; + return m_hmd && m_comp && comp_attempts < 10; } diff --git a/src/hmd.h b/src/hmd.h index 04cc130..0dee07d 100644 --- a/src/hmd.h +++ b/src/hmd.h @@ -1,84 +1,23 @@ #pragma once #include "rtt.h" -struct Controller -{ - enum class Button : uint64_t - { - Trigger = 0x200000000, - Pad = 0x100000000, - Menu = 0x000000002, - Grip = 0x000000004, - }; - enum class ButtonAxis : uint8_t - { - Trigger = 1, - Pad = 0, - }; - enum class Action - { - Press, - Release, - }; - int index = 0; - bool active = false; - std::map buttons; - std::map buttons_axis; - uint64_t buttons_bits{ 0 }; - glm::vec2 axis[5]; - glm::mat4 xform{ 1 }; - glm::vec3 pos{ 0 }; - glm::vec3 rot{ 0 }; - vr::VRControllerState_t state; - bool valid = false; - int role = 0; - - void update(const glm::mat4& m) - { - xform = m; - pos = glm::vec3(m[3]); - //float sx = glm::length(glm::vec3(m[0])); - //float sy = glm::length(glm::vec3(m[1])); - //float sz = glm::length(glm::vec3(m[2])); - glm::extractEulerAngleXYZ(m, rot.x, rot.y, rot.z); - } - -}; - struct Vive { int comp_attempts = 0; - uint32_t eyeWidth = 0, eyeHeight = 0; - RTT eyes[2]; - vr::IVRSystem* hmd = nullptr; - vr::IVRCompositor* comp = nullptr; - vr::IVRSettings* settings = nullptr; - glm::vec3 euler{ 0 }; - glm::vec4 background{ .5, .2, .2, 1 }; - float yaw_offset = 0; - glm::mat4 view[2]; - glm::mat4 proj[2]; - glm::mat4 pose; - Controller controllers[32]; - Controller trackers[32]; - bool swap_controllers = false; - bool active = false; - std::string dev_serial{ "0000001" }; - std::string dev_model{ "Vive" }; - std::string dev_tracksys{ "lighthouse" }; - std::string dev_manufacturer{ "HTC" }; - std::function on_draw = nullptr; - std::function on_button = nullptr; - std::function on_button_axis = nullptr; + uint32_t m_eye_width = 0, m_eye_height = 0; + RTT m_eyes[2]; + vr::IVRSystem* m_hmd = nullptr; + vr::IVRCompositor* m_comp = nullptr; + vr::IVRSettings* m_settings = nullptr; + glm::mat4 m_view[2]; + glm::mat4 m_proj[2]; + glm::mat4 m_pose; + bool m_active = false; + std::function on_draw = nullptr; - Vive(); bool Initialize(); void Terminate(); - void ResetYaw(); void Update(); void Draw(); - std::string ReadPropString(vr::TrackedDeviceIndex_t nDevice, vr::ETrackedDeviceProperty p); bool Valid(); }; - - diff --git a/src/main.cpp b/src/main.cpp index b0b890f..f408856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -718,31 +718,6 @@ int main(int argc, char** argv) LOG("start hmd render thread"); App::I.has_vr = true; - bool trigger_down = false; - cbuffer controller_points; - glm::vec3 controller_last_point; - vive->on_button_axis = [&](const Controller& c, Controller::ButtonAxis b, Controller::Action a) { - if (b == Controller::ButtonAxis::Trigger) - { - if (a == Controller::Action::Press) - { - async_lock(); - Canvas::I->stroke_start(vive->controllers[0].pos * 800.f, vive->controllers[0].axis[1].x, Canvas::I->m_current_brush); - async_unlock(); - controller_last_point = vive->controllers[0].pos * 800.f; - controller_points.clear(); - trigger_down = true; - } - if (a == Controller::Action::Release) - { - trigger_down = false; - async_lock(); - Canvas::I->stroke_end(); - async_unlock(); - } - } - }; - const float target_tick_rate = 90; unsigned long t0 = GetTickCount(); while (running && vive->Valid()) @@ -752,25 +727,9 @@ int main(int argc, char** argv) float dt = (float)(t1 - t0) / 1000.0f; vive->Update(); - App::I.vr_active = vive->active; - App::I.vr_controller = vive->controllers[0].xform; - App::I.vr_controller_pos = vive->controllers[0].pos; + App::I.vr_active = vive->m_active; - if (trigger_down) - { - controller_points.add(vive->controllers[0].pos * 800.f); - auto p = controller_points.average(); - if (glm::distance(p, controller_last_point) > 1) - { - async_lock(); - Canvas::I->stroke_update(p, vive->controllers[0].axis[1].x); - async_unlock(); - controller_last_point = p; - App::I.redraw = true; - } - } - - if (vive->active) + if (vive->m_active) { async_lock(); vive->Draw(); @@ -1135,29 +1094,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) return DefWindowProc(hWnd, msg, wp, lp); } -int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, - _In_ LPSTR lpCmdLine, _In_ int nShowCmd) +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { - LPWSTR *szArgList{ nullptr }; - int argc{ 0 }; - char** argv{ nullptr }; - - szArgList = CommandLineToArgvW(GetCommandLine(), &argc); - if (szArgList == NULL) - { - MessageBox(NULL, L"Unable to parse command line", L"Error", MB_OK); - return 10; - } + LPWSTR *wargs = nullptr; + char** argv = nullptr; + int argc = 0; + // convert args from char to wchar + wargs = CommandLineToArgvW(GetCommandLine(), &argc); argv = new char*[argc + 1]; for (int i = 0; i < argc; i++) { - auto len = wcslen(szArgList[i]) + 1; + auto len = wcslen(wargs[i]) + 1; argv[i] = new char[len]; - wcstombs_s(nullptr, argv[i], len, szArgList[i], len); + wcstombs_s(nullptr, argv[i], len, wargs[i], len); } - LocalFree(szArgList); + LocalFree(wargs); return main(argc, argv); }