Ti.UI.Viewでパーティクルベンチマーク
Ti.UI.Viewで点を描いて動かすとどれくらいFPSがでるか計測してみた。
以下がソース。
実行すると黒い点が画面上を飛び回ります。
var window = Titanium.UI.createWindow({ backgroundColor:'#fff' }); var view_num = 10; var points = []; for( var i = 0; i < view_num; i++){ var point = Ti.UI.createView({ backgroundColor : 'red', width: 2, height: 2, center: window.center }); var sign = (parseInt(Math.random()*10)%2) ? 1 : -1; point.vx = sign * parseInt(Math.random()*10); var sign = (parseInt(Math.random()*10)%2) ? 1 : -1; point.vy = sign * parseInt(Math.random()*10); points.push( point ); window.add( point ); } var fps_text = Ti.UI.createTextField({ value : '0 fps', left : 0, }); window.add( fps_text ); function render(){ for( var i = 0; i < points.length; i++){ var point = points[i]; var newx = point.center.x + point.vx; var newy = point.center.y + point.vy; if( newx <= 0 ){ newx = 0; point.vx *= -1; } else if( window.width <= newx ){ newx = window.width; point.vx *= -1; } if( newy <= 0 ){ newy = 0; point.vy *= -1; } else if( window.height <= newy ){ newy = window.height; point.vy *= -1; } point.center = { x : newx, y : newy }; } } window.open(); var last_time = new Date().getTime(); var elapsed_time = 0; var framecount = 0; setInterval( function(){ render(); var now = new Date().getTime(); elapsed_time += (now - last_time); last_time = now; framecount++; if( 990 <= elapsed_time ){ fps_text.value = '' + framecount + ' fps'; framecount = 0; elapsed_time = 0; } }, 33);
開発メモ
<uses-library android:name="com.google.android.maps" />
uses-libraryタグはapplicationタグの中に書かないと動かない。外に書いてもエラーはでないので注意。
参考:
http://developer.android.com/resources/tutorials/views/hello-mapview.html
ndkでビルドするときのオプションメモ
$export ANDROID_ROOT=android-ndk-r4b/build $export PATH=android-ndk-r4b/build/prebuilt/darwin-x86/arm-eabi-4.4.0/bin $./configure --host=arm-eabi CPP=arm-eabi-cpp CC=arm-eabi-gcc CFLAGS="-mandroid --sysroot=$ANDROID_ROOT/platforms/android-3/arch-arm" CPPFLAGS="-I$ANDROID_ROOT/platforms/android-3/arch-arm/usr/include"
参考:
http://blog.kmckk.com/archives/2918551.html
http://warpedtimes.wordpress.com/2010/02/03/building-open-source-libraries-with-android-ndk/
GPSとネットワークと実機デバッグを有効にする
Androidで開発するときはAndroidManifest.xmlにどの機能を有効にするのか書く必要があるっぽい
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example" android:versionCode="1" android:versionName="1.0"> <!-- debuggable=trueを書かないと実機デバッグができない --> <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /> <!-- GPSを使用する。 これを書かないとセキュリティ例外になる --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <!-- GPSを使用する。 これを書かないとセキュリティ例外になる --> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/> <!-- HTTPで通信する。 これを書かないとセキュリティ例外になる --> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
C++でnode.jsのaddonを書いてみた
addonを書く上で必要なことは基本ここに書いてあるんだけど今のバージョン(v0.23)だと若干便利マクロが増えてるみたい。
今回は渡された文字列とカウンタを表示するだけの簡単なクラスを作った。 JavaScriptのmoduleで書くとこんな感じ
function Echo(){ this.i = 0 } Echo.prototype.print = function(s){ console.log( s + ' ' + this.i ); this.i++; } exports.Echo = Echo;
同じことをC++のaddonで書くと以下のような感じ
※重要そうなところはコメントで。
echo.h:
#ifndef _ECHO_ #define _ECHO_ #include <node.h> #include <v8.h> using namespace v8; using namespace node; // node.js が用意しているObjectWrapを継承することで自作のクラスもGC対象にする class Echo : ObjectWrap { public: // node.jsにメソッドを登録するためにstaticにしてる // インスタンスを作る関数はNewにするのが通例っぽい static Handle<Value> New(const Arguments& args); static Handle<Value> Print(const Arguments& args); Echo() : count(0) {}; ~Echo(); private: int count; void print(const char *s); }; static void AddonInitialize( Handle<Object> target ); #endif
echo.cc:
#include <v8.h> #include <node.h> #include <iostream> #include "echo.h" using namespace node; using namespace v8; using namespace std; Handle<Value> Echo::New(const Arguments& args){ HandleScope scope; // v8のお約束っぽい。 このscopeがないとどうなるのかよくわからない。。。 Echo *p = new Echo(); p->Wrap(args.This()); // thisとEchoのインスタンスを対応付ける return args.This(); } Handle<Value> Echo::Print(const Arguments& args){ HandleScope scope; if( args.Length() != 1 || !args[0]->IsString() ){ // 引数がおかしい場合は例外を投げる return ThrowException(Exception::Error(String::New("Bad argument."))); } Echo *o = ObjectWrap::Unwrap<Echo>(args.This()); // char* を取り出すためにUtf8Valueに変換。 // この辺はv8のクラスリファレンスを読むと色々わかるかも String::Utf8Value str(args[0]->ToString()); o->print(*str); return Undefined(); } void Echo::print(const char* s){ cout << s << " " << count << endl; count++; } Echo::~Echo(){ // デストラクタはnode.js側でGCが起きると呼ばれる cout << "delete" << endl; } void AddonInitialize( Handle<Object> target ){ HandleScope scope; // node.jsでnew Echoされたときの関数を登録 Local<FunctionTemplate> t = FunctionTemplate::New(Echo::New); // ObjectWrapを継承してる場合必要なお約束 t->InstanceTemplate()->SetInternalFieldCount(1); // console.log等で表示するクラス名の登録。無くても大丈夫。 t->SetClassName(String::NewSymbol("Echo")); // Echo.prototype.print に Echo::Printを登録 NODE_SET_PROTOTYPE_METHOD(t, "print", Echo::Print); // exports.Echo に Echoクラスを登録 target->Set(String::New("Echo"), t->GetFunction()); } // addon名(echo)と初期化関数(AddonInitialize)を登録 NODE_MODULE(echo, AddonInitialize);
wscript:
srcdir = '.' blddir = 'build' VERSION = '0.0.1' def set_options(opt): opt.tool_options('compiler_cxx') def configure(conf): conf.check_tool('compiler_cxx') conf.check_tool('node_addon') def build(bld): obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') obj.target = 'echo' obj.source = 'echo.cc'
上記3つのファイル(echo.h, echo.cc, wscript)を同じディレクトリに置いてnode-wafコマンドを実行するとコンパイルされてbuild/default以下にecho.nodeという名前でaddonが作成される。
node-waf実行例:
bash$ ls echo.h echo.cc wscript bash$ node-waf Waf: Entering directory `/home/bongole/test_addon/build' [1/2] cxx: echo.cc -> build/default/echo_1.o [2/2] cxx_link: build/default/echo_1.o -> build/default/echo.node Waf: Leaving directory `/home/bongole/test_addon/build' 'build' finished successfully (0.491s)
addonを実際に使ってみるには、同じディレクトリに以下のようなJavaScriptのファイルを作ってnodeコマンドで実行する。
test.js:
var Echo = require('./build/default/echo').Echo; var o1 = new Echo(); o1.print("hello"); o1.print("world"); var o2 = new Echo(); o2.print("hello"); o2.print("again"); o1 = null; o2 = null; // GCが発生するまで待つ setTimeout(function(){}, 10000);
test.jsの実行例:
bash$ ls build echo.h echo.cc wscript test.js bash$ node ./test.js hello 0 world 1 hello 0 again 1 delete delete
ちゃんと別々のインスタンスになってるし、GCでデストラクタが呼ばれてるみたい。
まとめ:
- node.jsのaddon書くにはv8の知識が結構必要
- でも作法を覚えればそんなに難しくない!
参考URL:
今すぐwebサーバーが必要な人のためのワンライナー
カレントディレクトリにあるファイルを今すぐHTTP経由でブラウザに表示させたいと思ったら
ruby -rwebrick -e 's = WEBrick::HTTPServer.new(:Port=>8888, :DocumentRoot=>Dir.pwd);trap("INT"){s.shutdown};s.start'
を実行して http://localhost:8888/hoge.html をブラウザに打ち込め!