openFrameworksでマルチタッチしてみた (Mac only)

Mac純正のマルチタッチフレームワークであるMultitouchSupport.frameworkを使ってマルチタッチをしてみる

参考サイトは死んでるので、覚えてる範囲で...

 

必要なもの

  1. openFrameworks本体
  2. ofxVectorMath (Addon)
  3. MultitouchSupport.framework (/System/Library/PrivateFrameworks/にある)
  4. ofxOsc (任意)

手順

  1. ofxVectorMath、MultitouchSupport.frameworkとofxOscをXcodeのプロジェクトに入れる...ドラッグするだけ
    こんな感じになる

    f:id:sngymn:20130303015719p:plain

  2. testApp.cppをtestApp.mmに変更する
    一応、ファイルタイプがObjective-C++ Sourceになってるか確認
  3. コードを書く
#pragma once

#include "ofMain.h"
#include "ofxOsc.h"

#define TUIOPORT 3333

class testApp : public ofBaseApp{
public:
    void setup();
	void update();
	void draw();
		
	void keyPressed(int key);
	void keyReleased(int key);
	void mouseMoved(int x, int y);
	void mouseDragged(int x, int y, int button);
	void mousePressed(int x, int y, int button);
	void mouseReleased(int x, int y, int button);
	void windowResized(int w, int h);
			
    int width, height;
	ofxOscSender send;
};

#include "testApp.h"
#include "ofVectorMath.h"

extern "C" {
    typedef struct { float x,y; } mtPoint;
	typedef struct { mtPoint pos,vel; } mtReadout;
	typedef struct {
		int frame;
		double timestamp;
		int identifier, state, foo3, foo4;
		mtReadout normalized;
		float size;
		int zero1;
		float angle, majorAxis, minorAxis;
		mtReadout mm;
		int zero2[2];
		float unk2;
	}
	Finger;
	
	typedef void *MTDeviceRef;
	typedef int (*MTContactCallbackFunction)(int,Finger*,int,double,int);
	
	CFMutableArrayRef MTDeviceCreateList(void);
	void MTRegisterContactFrameCallback(MTDeviceRef, MTContactCallbackFunction);
	void MTDeviceStart(MTDeviceRef, int);
}


class TouchPoint {
public:
	ofVec2f pos;
	ofVec2f vel;
	float size;
	int id;
	bool enable;
	float phase;
	float freq, amp;
	float trem_phase;
	int stat;
};

vector<TouchPoint> touchPoints;

int mtCallback(int device, Finger *data, int nFingers, double timestamp, int frame) {
	for (int i = 0; i < touchPoints.size(); i  ++) {
		touchPoints[i].enable = false;
	}
	for (int i=0; i<nFingers; i++) {
		Finger *f = &data[i];
		
		/*
		 printf("Frame %7d: Angle %6.2f, ellipse %6.3f x%6.3f; "
		 "position (%6.3f,%6.3f) vel (%6.3f,%6.3f) "
		 "ID %d, state %d [%d %d?] size %6.3f, %6.3f?n",
		 f->frame,
		 f->angle * 90 / atan2(1,0),
		 f->majorAxis,
		 f->minorAxis,
		 f->normalized.pos.x,
		 f->normalized.pos.y,
		 f->normalized.vel.x,
		 f->normalized.vel.y,
		 f->identifier, f->state, f->foo3, f->foo4,
		 f->size, f->unk2);
		 */
		
		TouchPoint &t = touchPoints[f->identifier];
		t.pos.x = f->normalized.pos.x;
		t.pos.y = 1 - f->normalized.pos.y;
		t.size = f->size;
		t.enable = true;
		t.id = f->identifier;
		t.vel.x = f->normalized.vel.x;
		t.vel.y = f->normalized.vel.y;
		t.stat = f->foo3;
	}
	return 0;
}


void testApp::setup() {
	touchPoints.resize(20);
	
	NSMutableArray* deviceList = (NSMutableArray*)MTDeviceCreateList();
	for(int i = 0; i < [deviceList count]; i ++) { 
		MTRegisterContactFrameCallback([deviceList objectAtIndex:i], mtCallback);
		MTDeviceStart([deviceList objectAtIndex:i], 0);
	}
	
	ofEnableSmoothing();
	ofEnableAlphaBlending();
	ofSetVerticalSync(true);
	ofSetFrameRate(60);
	
	ofHideCursor();
	
	ofBackground(0, 0, 0);
	
	ofSetColor(255, 255, 255);
	ofNoFill();
	
	width = ofGetWidth();
	height = ofGetHeight();
	send.setup("127.0.0.1", TUIOPORT);
}


void testApp::update() {	
	
}

void testApp::draw() {
	for (int i = 0; i < touchPoints.size(); i++)
	{
		TouchPoint &t = touchPoints[i];
		
		if (t.enable == false) {

			continue;
		}
		
		float xx = t.pos.x * width;
		float yy = t.pos.y * height;
		ofCircle(xx, yy, t.size * 50);
		
		ofDrawBitmapString("x: " + ofToString(t.pos.x*width), xx-10, yy-15);
		ofDrawBitmapString("y: " + ofToString(t.pos.y*height), xx-10, yy);
		ofDrawBitmapString("ID :" + ofToString(t.id), xx-10, yy+15);
		ofDrawBitmapString("ID :" + ofToString(t.id), xx-10, yy+15);
		cout << t.stat << endl;
		
		ofxOscMessage m;
		m.setAddress("/tuio/2Dcur");
		m.addStringArg("set");
		m.addIntArg(t.id);
		m.addFloatArg(t.pos.x);
		m.addFloatArg(t.pos.y);
		m.addFloatArg(t.vel.x);
		m.addFloatArg(t.vel.y);
		m.addFloatArg(t.vel.x * t.vel.y);
		send.sendMessage(m);
	}
}

void testApp::keyPressed(int key) {
	if(key == 'f')
		ofToggleFullscreen();
	if (key == 'i') {
		width = ofGetWidth();
		height = ofGetHeight();
	}
}

void testApp::keyReleased(int key) {
}

void testApp::mouseMoved(int x, int y){
}

void testApp::mouseDragged(int x, int y, int button) {
}

void testApp::mousePressed(int x, int y, int button) {
}

void testApp::mouseReleased(int x, int y, int button) {
}

void testApp::windowResized(int w, int h) {
}

これを実行すればこんな感じになるはず...

f:id:sngymn:20130303020400p:plainメンバ変数をPrivateにしてないのは(ry

oFの仕様なのか、ofGetWidth()とかはofToggleFullscreen()を実行しても更新されないようです