Create a gist now

Instantly share code, notes, and snippets.

@voidproc /leap.cpp
Last active Nov 25, 2016

What would you like to do?
Application Launcher with Leap Motion + Siv3D
#define NOMINMAX
#define STRICT
#include <windows.h>
#include <Siv3D.hpp>
#include <HamFramework.hpp>
#include <Siv3DAddon/LeapMotion.hpp>
// Leap Motion で アプリケーションランチャー
//
// ジェスチャーでアプリケーションを実行します。
//
// 本アプリにおけるジェスチャー:
// 1. ジェスチャーを開始(手を開く動作)
// 2. 手を10cm以上移動
// 3. ジェスチャーを終了(手を握る動作)
//
// 手を移動する角度(8方向)により実行するコマンドを選択します。
//
//
// ※アプリケーションが非アクティブになっても Leap Motion での検出を続ける場合は
// LeapMotion.hpp の LeapMotionDevice::init() に以下の行を追加
// m_controller.setPolicyFlags( Leap::Controller::PolicyFlag::POLICY_BACKGROUND_FRAMES);
struct GestureMarker : public IEffect
{
GestureMarker(const Vec2& pos)
: pos(pos)
{
}
bool update(double t)
{
Circle(pos, 4.0 + t/0.3 * 200.0).drawFrame(30.0 * (1.1 - t/0.3), 0.0, Color(Palette::Yellow, 255 - 200 * (1.1 - t/0.3)));
return t < 0.3;
}
Vec2 pos;
};
struct ExecGestureCommand : public IEffect
{
bool update(double t)
{
Window::BaseClientRect().draw(Color(Palette::Lime, 128 * (1.1 - t/0.3)));
return t < 0.3;
}
};
double startAngle(const int index, const int div = 8)
{
return Pi - (TwoPi / div / 2 + TwoPi / div * (index - 1));
}
void drawCircleMenu(const int index, const int div = 8)
{
const double ang = startAngle(index, div);
Circle(Window::BaseCenter(), 220.0)
.drawFrame(100.0, 0.0, Color(80, 128))
.drawArc(Pi - ang, TwoPi / div, 100.0, 0.0, Palette::White);
}
struct Command
{
String path;
};
class CommandList
{
public:
CommandList()
{
cmd_.resize(N);
cmd_[0].path = L"calc";
cmd_[1].path = L"mspaint";
cmd_[2].path = L"notepad";
cmd_[3].path = L"cmd";
cmd_[4].path = L"wmplayer";
cmd_[5].path = L"iexplore";
cmd_[6].path = L"explorer";
cmd_[7].path = L"excel";
}
bool execute(const int i)
{
::ShellExecute(nullptr, nullptr, cmd_[i].path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
return true;
}
const FilePath& path(const int i)
{
return cmd_[i].path;
}
private:
const int N = 8;
Array<Command> cmd_;
};
void Main()
{
ScalableWindow::Setup(600, 600);
Window::Resize(300, 300);
FontAsset::Register(L"menu", 36, Typeface::Bold);
Effect effect;
LeapMotion::RegisterAddon();
String state = L"";
Vec2 gestureBase; //ジェスチャ開始位置
int beginGestureWait = 0; //ジェスチャ開始までの待ち時間用
CommandList commands;
while (System::Update())
{
{
const auto transformer = ScalableWindow::CreateTransformer();
// 手が検出されない場合はジェスチャの状態をリセットする
if (LeapMotion::Hands().empty())
{
state = L"";
// BG
Window::BaseClientRect().draw(Color(128));
}
else
{
// 手が検出された場合は、1本目の手のジェスチャを監視
for (const auto& hand : LeapMotion::Hands())
{
const Vec2 pos = hand.stabilizedPos.xy();
if (state == L"begin")
{
// BG
Window::BaseClientRect().draw(Color(128, 80 * ((System::FrameCount() / 2) % 2)));
// ジェスチャ開始位置と現在の手との距離・角度
const Circular d = pos - gestureBase;
// ジェスチャの有効範囲に入っているか?
if (d.r > 100)
{
const int DIV = 8;
int index = ((int)(4.5 - d.theta / (TwoPi / DIV)) % 8); // 0..DIV-1
drawCircleMenu(index, DIV);
FontAsset(L"menu")(commands.path(index)).drawCenter(Window::BaseCenter());
// ジェスチャコマンド実行
if (hand.grabStrength > 0.8)
{
effect.add<ExecGestureCommand>();
commands.execute(index);
state = L"";
beginGestureWait = 0;
}
}
// ジェスチャ中止
if (hand.grabStrength > 0.8)
{
state = L"";
}
// ジェスチャの中心
Circle(Window::BaseCenter().movedBy(gestureBase.x, +300 - gestureBase.y), 30.0).drawFrame(4.0, 0.0, Color(Palette::Yellow, 100));
}
// ジェスチャを開始
if (state == L"")
{
if (hand.grabStrength < 0.1)
{
if (++beginGestureWait > 16)
{
state = L"begin";
gestureBase = pos;
effect.add<GestureMarker>(Vec2(Window::BaseCenter().x + pos.x, Window::BaseCenter().y + 300 - pos.y));
}
}
else
{
beginGestureWait = 0;
}
}
//
Circle(Window::BaseCenter().x + pos.x, Window::BaseCenter().y + 300 - pos.y, 20.0).draw(Color(255, 100));
break;
}
}
effect.update();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment