diff --git a/src/app.cpp b/src/app.cpp index 11692d9..c47ab3a 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -116,6 +116,7 @@ void App::initAssets() sampler_stencil.create(GL_LINEAR, GL_REPEAT); sampler_linear.create(GL_LINEAR); m_face_plane.create<1>(2, 2); + //sphere.create<8, 8>(1); LOG("initializing assets load uvs texture"); LOG("initializing assets completed"); } diff --git a/src/app.h b/src/app.h index 20f78e2..ac2f808 100644 --- a/src/app.h +++ b/src/app.h @@ -52,6 +52,7 @@ public: Sampler sampler_stencil; Sampler sampler_linear; ui::Plane m_face_plane; + //ui::Sphere sphere; LayoutManager layout; NodeMessageBox* msgbox; NodeSettings* settings; @@ -82,6 +83,10 @@ public: bool redraw = true; bool animate = false; bool ui_visible = true; + bool vr_active = false; + glm::mat4 vr_controller; + glm::vec3 vr_controller_pos; + float vr_pressure = 1.f; glm::mat4 vr_rot{ 0 }; glm::mat4 vr_uirot{ 0 }; glm::vec2 cursor{ 0, 0 }; diff --git a/src/app_vr.cpp b/src/app_vr.cpp index aa3f7a8..2b88045 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -219,6 +219,41 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat m_face_plane.draw_fill(); } + // draw the motion controller sphere +/* + { + auto mvp = proj * camera * glm::translate(glm::normalize(vr_controller_pos)); + ui::ShaderManager::use(kShader::Color); + ui::ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 }); + ui::ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.025))); + sphere.draw_fill(); + } +*/ + + // draw the motion controller brush + { + auto pos = glm::translate(glm::normalize(vr_controller_pos)); + ui::ShaderManager::use(ui::kShader::StrokePreview); + ui::ShaderManager::u_int(ui::kShaderUniform::Tex, 0); + ui::ShaderManager::u_float(ui::kShaderUniform::Alpha, canvas->m_canvas->m_current_brush.m_tip_flow); + auto tip_color = glm::vec4(glm::vec3(canvas->m_canvas->m_current_brush.m_tip_color), 1); + ui::ShaderManager::u_vec4(ui::kShaderUniform::Col, tip_color); + ui::ShaderManager::u_mat4(ui::kShaderUniform::MVP, + proj * camera * pos * + glm::inverse(glm::lookAt({ 0, 0, 0 }, vr_controller_pos, { 0, 1, 0 })) * + //glm::scale(glm::vec3(0.1)) * + glm::scale(glm::vec3(canvas->m_canvas->m_current_brush.m_tip_size * 800.f / App::I.height)) * + glm::eulerAngleZ(canvas->m_canvas->m_current_brush.m_tip_angle * (float)(M_PI * 2.0)) + ); + glEnable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); + auto& tex = TextureManager::get(canvas->m_canvas->m_current_brush.m_tex_id); + tex.bind(); + sampler_linear.bind(0); + m_face_plane.draw_fill(); + tex.unbind(); + } + /* for (auto& mode : *m_canvas->m_mode) mode->on_Draw(ortho_proj, proj, camera); diff --git a/src/brush.cpp b/src/brush.cpp index 696b6f5..15e2e76 100644 --- a/src/brush.cpp +++ b/src/brush.cpp @@ -9,7 +9,7 @@ void ui::BrushMesh::draw(const std::vector& samples, const glm::ma for (const auto& s : samples) { auto mvp = proj * - glm::translate(glm::vec3(s.pos, 0)) * + glm::translate(s.pos) * glm::scale(glm::vec3(s.size, s.size, 1)) * glm::eulerAngleZ(s.angle); attributes.emplace_back(instance_t{ mvp, s.flow }); @@ -126,12 +126,12 @@ bool ui::BrushMesh::create() return true; } -ui::StrokeSample ui::Stroke::randomize_sample(const glm::vec2& pos, float pressure, float curve_angle) +ui::StrokeSample ui::Stroke::randomize_sample(const glm::vec3& pos, float pressure, float curve_angle) { auto rnd_nor = [&] { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1] //auto rnd_neg = [&] { return float((double)prng() / (double)prng.max() * 2.0 - 1.0); }; // normalized [-1, +1] auto rnd_rad = [&] { return float((double)prng() / (double)prng.max() * M_PI * 2.0); }; // normalized [0, 2pi] - auto rnd_vec = [&] { float rad = rnd_rad(); return glm::vec2(cosf(rad), sinf(rad)); }; // normalized direction vector + auto rnd_vec = [&] { float rad = rnd_rad(); return glm::vec3(cosf(rad), sinf(rad), 0); }; // normalized direction vector float size_dyn = m_brush.m_tip_size_pressure ? pressure : 1.f; float flow_dyn = m_brush.m_tip_flow_pressure ? pressure : 1.f; @@ -200,7 +200,7 @@ void ui::Stroke::reset(bool clear_keypoints /*= false*/) if (clear_keypoints) m_keypoints.clear(); } -void ui::Stroke::add_point(glm::vec2 pos, float pressure) +void ui::Stroke::add_point(glm::vec3 pos, float pressure) { #ifdef __IOS__ m_curve = glm::min(m_curve + 0.1f, 1.f); diff --git a/src/brush.h b/src/brush.h index 7fc60cc..98f7d14 100644 --- a/src/brush.h +++ b/src/brush.h @@ -42,8 +42,8 @@ public: struct StrokeSample { glm::vec3 col = { 0, 0, 0 }; - glm::vec2 pos = { 0, 0 }; - glm::vec2 origin = { 0,0 }; + glm::vec3 pos = { 0, 0, 0 }; + glm::vec3 origin = { 0, 0, 0 }; float size = 0; float flow = 0; float angle = 0; @@ -76,7 +76,7 @@ class Stroke public: struct Keypoint { - glm::vec2 pos = { 0, 0 }; + glm::vec3 pos = { 0, 0, 0 }; float pressure = 0; float dist = 0; }; @@ -96,16 +96,16 @@ public: cbuffer m_hsv_jitter; StrokeSample m_prev_sample; std::vector m_keypoints; - std::vector> m_hold_points; + std::vector> m_hold_points; std::vector m_samples; int m_last_kp; std::minstd_rand prng; void start(const ui::Brush& brush); - void add_point(glm::vec2 pos, float pressure); + void add_point(glm::vec3 pos, float pressure); void reset(bool clear_keypoints = false); bool has_sample(); std::vector compute_samples(); - StrokeSample randomize_sample(const glm::vec2& pos, float pressure, float curve_angle); + StrokeSample randomize_sample(const glm::vec3& pos, float pressure, float curve_angle); }; NS_END diff --git a/src/canvas.cpp b/src/canvas.cpp index fb88f2b..2510ccf 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -361,7 +361,7 @@ void ui::Canvas::stroke_draw() glm::vec2 bb_max(0, 0); for (int j = 0; j < 4; j++) { - auto p = (m_mixer_sample.pos + off[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1)) / zoom; + auto p = (xy(m_mixer_sample.pos) + off[j] * glm::orientate2(-s.angle) + glm::vec2(0, 1)) / zoom; UV2[j] = p / sz; bb_min = glm::max({ 0, 0 }, glm::min(bb_min, p)); bb_max = glm::min(sz, glm::max(bb_max, p)); @@ -427,8 +427,18 @@ void ui::Canvas::stroke_draw() for (int j = 0; j < 4; j++) { glm::vec3 ray_origin, ray_dir; - point_unproject(s.pos + off[j] * glm::orientate2(-s.angle), { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir); - + if (s.pos.z == 0) + { + point_unproject(xy(s.pos) + off[j] * glm::orientate2(-s.angle), { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir); + } + else + { + auto m = glm::inverse(glm::lookAt({ 0, 0, 0 }, s.pos, { 0, 1, 0 })); + glm::vec3 off_3d = m * glm::vec4(off[j], 0, 1); + ray_origin = glm::vec3(0); + ray_dir = s.pos + off_3d; + } + glm::vec3 hit; if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit)) { @@ -498,7 +508,7 @@ void ui::Canvas::stroke_draw() } m_mixer_sample = s; - } + } glDisable(GL_BLEND); @@ -742,11 +752,11 @@ void ui::Canvas::stroke_commit() action->m_stroke = std::move(m_current_stroke); ActionManager::add(action); } -void ui::Canvas::stroke_update(glm::vec2 point, float pressure) +void ui::Canvas::stroke_update(glm::vec3 point, float pressure) { m_current_stroke->add_point(point, pressure); } -void ui::Canvas::stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush) +void ui::Canvas::stroke_start(glm::vec3 point, float pressure, const ui::Brush& brush) { // need to commit this now before starting a new stroke if (m_current_stroke && m_commit_delayed) diff --git a/src/canvas.h b/src/canvas.h index 7c6f6c7..29f2d17 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -189,8 +189,8 @@ public: void layer_add(std::string name); void layer_order(int idx, int pos); void layer_merge(int source_idx, int dest_idx); - void stroke_start(glm::vec2 point, float pressure, const ui::Brush& brush); - void stroke_update(glm::vec2 point, float pressure); + void stroke_start(glm::vec3 point, float pressure, const ui::Brush& brush); + void stroke_update(glm::vec3 point, float pressure); void stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz); void stroke_draw(); void stroke_end(); diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp index 41a38ea..b17561f 100644 --- a/src/canvas_modes.cpp +++ b/src/canvas_modes.cpp @@ -46,7 +46,7 @@ void CanvasModeBasicCamera::on_MouseEvent(MouseEvent* me, glm::vec2& loc) case kEventType::MouseMove: if (m_draggingR) { - auto dir = App::I.has_vr ? glm::vec2(1, 1) : glm::vec2(-1, -1); + auto dir = (App::I.has_vr && App::I.vr_active) ? glm::vec2(1, 1) : glm::vec2(-1, -1); canvas->m_pan = m_pan_start + (me->m_pos - m_dragR_start) * dir * (canvas->m_cam_fov / 85.f); auto angle = canvas->m_pan * 0.003f; canvas->m_cam_rot = glm::eulerAngleXY(angle.y, angle.x); @@ -108,7 +108,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc) } else { - canvas->stroke_start(loc, me->m_pressure, canvas->m_current_brush); + canvas->stroke_start({ loc, 0 }, me->m_pressure, canvas->m_current_brush); } m_dragging = true; node->mouse_capture(); @@ -150,7 +150,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc) break; case kEventType::MouseMove: if (m_dragging && !m_picking && !m_resizing) - canvas->stroke_update(loc, me->m_pressure); + canvas->stroke_update({ loc, 0 }, me->m_pressure); if (m_dragging && m_picking) { glm::vec4 pix = canvas->pick_get(loc); @@ -250,8 +250,8 @@ void CanvasModeLine::on_MouseEvent(MouseEvent* me, glm::vec2& loc) node->mouse_release(); if (m_dragging) { - canvas->stroke_start(m_drag_start, 1.f, canvas->m_current_brush); - canvas->stroke_update(m_drag_pos, 1.f); + canvas->stroke_start({ m_drag_start, 0 }, 1.f, canvas->m_current_brush); + canvas->stroke_update({ m_drag_pos, 0 }, 1.f); canvas->stroke_end(); } m_dragging = false; diff --git a/src/hmd.cpp b/src/hmd.cpp index 1db5062..46e6be3 100644 --- a/src/hmd.cpp +++ b/src/hmd.cpp @@ -9,6 +9,14 @@ Vive::Vive() 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; @@ -18,6 +26,8 @@ bool Vive::Initialize() comp = vr::VRCompositor(); if (!comp) return false; + + settings = vr::VRSettings(); hmd->GetRecommendedRenderTargetSize(&eyeWidth, &eyeHeight); LOG("Eye target resolution: %dx%d\n", eyeWidth, eyeHeight); @@ -37,22 +47,20 @@ bool Vive::Initialize() { if (hmd->GetTrackedDeviceClass(nDevice) == vr::TrackedDeviceClass_HMD) { - auto read_string = [nDevice, this](vr::ETrackedDeviceProperty p) -> std::string { - size_t len = hmd->GetStringTrackedDeviceProperty(nDevice, p, nullptr, 0); - std::string str(len, '\0'); - hmd->GetStringTrackedDeviceProperty(nDevice, p, (char*)str.data(), len); - return str; - }; - dev_tracksys = read_string(vr::Prop_TrackingSystemName_String); - dev_serial = read_string(vr::Prop_SerialNumber_String); - dev_model = read_string(vr::Prop_ModelNumber_String); - dev_manufacturer = read_string(vr::Prop_ManufacturerName_String); + 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); + 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); + return true; } @@ -66,9 +74,9 @@ void Vive::ResetYaw() yaw_offset = euler.y; } -void Vive::Draw() +void Vive::Update() { - if (!(hmd && comp && comp_attempts < 10)) + if (!(hmd && comp)) return; vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount]; @@ -77,9 +85,6 @@ void Vive::Draw() for (int eye = 0; eye < 2; ++eye) { - eyes[eye].bindFramebuffer(); - eyes[eye].clear(background); - glViewport(0, 0, eyes[eye].getWidth(), eyes[eye].getHeight()); // Get view and projection matrices vr::HmdMatrix44_t p = hmd->GetProjectionMatrix((vr::EVREye)eye, 0.2f, 1000.f); @@ -110,10 +115,11 @@ void Vive::Draw() 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]); proj[eye] = mat_proj; view[eye] = mat_eye * mat_pose; - pose = glm::make_mat4((float*)hmdPose); + pose = mat_pose; for (auto& c : controllers) c.valid = false; @@ -146,13 +152,32 @@ void Vive::Draw() c.active = true; c.valid = true; hmd->GetControllerState(nDevice, &c.state, sizeof(vr::VRControllerState_t)); - c.update(glm::make_mat4((float*)mat)); + 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; @@ -175,7 +200,11 @@ void Vive::Draw() } break; case vr::TrackedDeviceClass_HMD: - break; + { + auto level = hmd->GetTrackedDeviceActivityLevel(nDevice); + active = (level == vr::k_EDeviceActivityLevel_UserInteraction); + } + break; case vr::TrackedDeviceClass_Invalid: break; case vr::TrackedDeviceClass_GenericTracker: @@ -199,12 +228,26 @@ void Vive::Draw() { std::swap(controllers[0], controllers[1]); } + } +} + +void Vive::Draw() +{ + if (!(hmd && comp && comp_attempts < 10)) + return; + + for (int eye = 0; eye < 2; ++eye) + { + eyes[eye].bindFramebuffer(); + eyes[eye].clear(background); + glViewport(0, 0, eyes[eye].getWidth(), eyes[eye].getHeight()); if (on_draw) - on_draw(proj[eye], view[eye], mat_pose); + on_draw(proj[eye], view[eye], pose); 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) { diff --git a/src/hmd.h b/src/hmd.h index 310da8f..1421c60 100644 --- a/src/hmd.h +++ b/src/hmd.h @@ -10,6 +10,11 @@ struct Controller Menu = 0x000000002, Grip = 0x000000004, }; + enum class ButtonAxis : uint8_t + { + Trigger = 1, + Pad = 0, + }; enum class Action { Press, @@ -18,6 +23,7 @@ struct Controller 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 }; @@ -46,6 +52,7 @@ struct Vive 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; @@ -55,18 +62,22 @@ struct Vive 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; 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 cd48ee2..2763c2a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "texture.h" #include "image.h" #include "app.h" +#include "canvas.h" #include "keymap.h" #include "hmd.h" #include "../resource.h" @@ -715,6 +716,32 @@ int main(int argc, char** argv) BT_SetTerminate(); 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(); + ui::Canvas::I->stroke_start(vive->controllers[0].pos * 800.f, vive->controllers[0].axis[1].x, ui::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(); + ui::Canvas::I->stroke_end(); + async_unlock(); + } + } + }; + const float target_tick_rate = 90; unsigned long t0 = GetTickCount(); while (running && vive->Valid()) @@ -723,14 +750,37 @@ int main(int argc, char** argv) unsigned long t1 = GetTickCount(); float dt = (float)(t1 - t0) / 1000.0f; - async_lock(); - vive->Draw(); - async_unlock(); + 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; + + 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(); + ui::Canvas::I->stroke_update(p, vive->controllers[0].axis[1].x); + async_unlock(); + controller_last_point = p; + App::I.redraw = true; + } + } + + if (vive->active) + { + async_lock(); + vive->Draw(); + async_unlock(); + } const int framerate = (1.f / target_tick_rate) * 1000; const int diff = framerate - (t1 - t0); hmd_render_cv.wait_for(lock, std::chrono::milliseconds(diff)); } + App::I.vr_active = false; App::I.has_vr = false; async_lock(); vive->Terminate(); diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index f823b01..450936d 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -148,7 +148,7 @@ void NodeStrokePreview::handle_resize(glm::vec2 old_size, glm::vec2 new_size) m_stroke.reset(); m_stroke.start(m_brush); for (int i = 0; i < 20; i++) - m_stroke.add_point(BezierCurve::Bezier2D(kp, i / 20.f), 1.f); + m_stroke.add_point(glm::vec3(BezierCurve::Bezier2D(kp, i / 20.f), 0), 1.f); m_rtt.destroy(); m_rtt.create((int)new_size.x, (int)new_size.y); diff --git a/src/pch.h b/src/pch.h index cd01f2c..ea5fc3a 100644 --- a/src/pch.h +++ b/src/pch.h @@ -108,6 +108,7 @@ #include #include #include +#include #include #include