レイアウトエディタを使う

Eclipseの左側にあるPackage ExplorerからProject→res→layoutとたどると、
main.xmlがある。デフォルトの中身はこんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

この場合、画面上部にHello world的な文字列が出力される。
XMLでの編集も出来るけど、GUIによる見た目でのボタン配置にも対応している。
Graphical Layoutタブに切り替えれば、画面の配置をマウスで決定できる。

Graphical Layoutで設定可能な設定としては、Widgetの配置のほか、
画面の上部には以下のような設定が並んでいる。

  • 画面解像度(QVGAなど)
  • 画面の向き(Portrait=縦、またはLandscape=横)
  • 画面のテーマ(タイトルバーを隠す、白基調にする、など)
  • Androidのバージョン

作成したレイアウトは以下のようにして組み込める。ここではmybuttons.xmlを作成したものとする。
(大文字がファイル名に入ってはいけないらしい)

View myButtons = View.inflate(this, R.layout.mybuttons, null);
addContentView(myButtons, new LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));

OpenGLESで描画する

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setContentView(R.layout.main);
    }
}

Projectを作成すると、これは作成されている。
Activityは画面のレイアウトを決定するもの?Sceneのようなものか?

アプリを起動すると、まずonCreate()が呼ばれてくるらしい。

上記にGLSurfaceViewを導入することでOpenGLESによる描画ができるようになるらしい。
以下の通り。

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // フルスクリーン表示
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        
        MyRenderer renderer = new MyRenderer(this);
        GLSurfaceView glSurfaceView = new MyGLSurfaceView(this);
        glSurfaceView.setRenderer(renderer);
        setContentView(glSurfaceView);
    }
}

Rendererを生成して、それとGLSurfaceViewをsetRendererでくっつける。
setContentViewはViewをActivityに設定する。Viewは画面のパーツ。
ボタンなどもViewのサブクラス。

Rendererの実装は以下の通り。
3つの関数くらいは自動生成してくれるが、中身は自分で実装する。

public class MyRenderer implements GLSurfaceView.Renderer {

	// 自分で追加したコンストラクタ。コンテキストを保持するためのもの。
	public MyRenderer(Context context){
		this.mContext = context;		
	}
	
	@Override
	public void onDrawFrame(GL10 gl) {
		// TODO Auto-generated method stub
		// 描画処理を記述する。何度も呼び出される。

	}

	@Override
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		// TODO Auto-generated method stub
		// Viewport設定、画面サイズ設定などを行う。画面生成時、画面向き変更時に呼び出される。
	}

	@Override
	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		// TODO Auto-generated method stub
		// 初期化処理、テクスチャ生成処理などを行う。画面生成時に呼び出される。
		
	}

}

現在のシステムカウンタ値を取得する

ミリ秒 ms単位で現在のシステムカウンタ値を取得する方法

long nowTime = System.currentTimeMillis();

WindowsのGetTickCount()に相当するカウンタと思われます。
使い方も同じで、2回測定して引き算すれば経過時間を計れます。
描画性能測定には必須でしょう。

importの自動入力ショートカットキー

importで使用するクラスを自動で入力するショートカットキー。

Ctrl + Shift + O

例えば、Logを出力するために、

Log.i(...

と書いた時にLogの下に赤線が出るので、この時に上記キーを押すと赤線が消える。

その他、クラス名の補間にはCtrl + Spaceが使える。
新しいクラスを追加する時に、継承させたいあのクラスの名前が分からない・・・とか。

HelloGoogleMapsでドロイド君が出てこない

GoogleAndroid Developersでサンプル動かしていたら、
タイトルの件のとおり、ドロイド君が表示されない事象発生。


サンプルでは以下のコードが書かれている。

	public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
		super(defaultMarker);
		// TODO Auto-generated constructor stub
		mContext = context;
	}

これをこうする

	public HelloItemizedOverlay(Drawable defaultMarker, Context context) {
		super(boundCenterBottom(defaultMarker));
		// TODO Auto-generated constructor stub
		mContext = context;
	}

これで表示されるようになった。

大きな領域をクリアする

大量の領域をCPUのみでクリアする方法として、

1. memset
2. 32bit単位で書いていく方法
3. 32bit単位で書いて、それをmemcpyしていく。

があると思う。他にないかな。


1. memset

void *memset( void *dest, int c, size_t n );

アドレスdestからnバイト分、cで埋める。
cはint型だから通常4byteと思いきや、最下位1byteをコピーする。
仕様なのか実装依存なのか不明。

例:c=0x12345678とすると、0x78をひたすらコピーする。

したがって、0x12345678でクリアしたくても出来ない。
メモリ上の値は以下のようになってしまう。
78 78 78 78 78 78 78 78 ...
こういうのはできない。
78 56 34 12 78 56 34 12 ...

長所:高速
短所:多バイトの値でクリアしたい場合に使えない。


2. 32bit単位で書いていく方法

現在のCPUは大抵32bit単位でアクセスできるので、(最近は64か?)
その単位でメモリを埋めていく方法。

 for(i = 0;i < SIZE;i++) *(dest + i) = 0x12345678;

長所:実装が簡単で短い。32bit単位で任意の値を設定できる。
短所:低速


3. 32bit単位で書いて、それをmemcpyしていく。

 // 1番目の領域
 for(i = 0; i < AREA_1;i++) *(dest + i) = 0x12345678;
 // 残りの領域
 for(i = AREA_1; i < AREA_LAST; i += AREA_1)
   memcpy(dest + i, dest, AREA_1);

長所:やや高速で、多バイトの値でのクリアにも対応。
短所:AREAのサイズを決める基準が難しい。


というわけで、速さの順に並べると

memset > dword + memcpy > dword

となる。



memsetとかmemcpyが内部で何をやっているのかは、Cの実装次第ですが、
こんな感じ。ARMを想定。

memset:
・クリアする値にマスクして最下位1byteのみ抜き出す。(0x12345678→0x00000078)
・1byteを4byteに膨らまし(0x00000078→0x78787878)
・さらに、複数のレジスタにその値をコピーする。(r1=r2=0x78787878)
・値をセットしたい領域分ループして、そのレジスタ値をメモリにセットする。
レジスタを使用する量が多いほど、ループ量が少ない。
レジスタのビット数が多いほど、ループ量が少ない。

memcpy:
・コピーするサイズに応じて、使用するレジスタ数を決定
→出来るだけ多く使った方が効率がいい。
・複数のレジスタへコピー元から値を読み込む
・複数のレジスタからコピー先へ値を吐き出す。

ここで、複数のレジスタを用いるので、32bit単位でのクリアよりも
効率が良いってことなのだと思う。当たり前のことですが、メモ。

参考)
複数のレジスタの値を同時にメモリに吐き出す命令(STM命令)。
複数のメモリの値を同時にレジスタに読み込む命令(LDM命令)。


領域のクリアをする場合に、コンパイラが最適化して変な動きに
なるかもしれないので、(memsetが消えてしまうとか)
そうなると困るようなポインタはvolatile宣言しておいた方が良さそう。
ドライバ屋さんはそうしているのでしょうけれども。

VGBlendModeがよく分からない

Blendの概念がよく分からなかったので、丁寧に計算したメモ。


Alpha compositing - WikipediaとOpenVG仕様書を参考に
Porter-Duffによるブレンドを行う。
よく分からないので、実際に適当に計算してみる。


前提条件
不透過の背景(dst)に半透過で色を重ねる(src)。
色は青の背景に黄色で色を重ねることにする。

→srcα = 0.5, dstα = 1.0
→srcC = (1, 1, 0), dstC = (0, 0, 1)

最初に、色に対してαを乗算しておく。
OpenVGの仕様書ではpremultiplyとかかれている。
(premultiplyしない方法も書かれている)
srcC' = (0.5, 0.5, 0), dstC' = (0, 0, 1)


1.VG_BLEND_SRC_OVER:

outαは以下の式で求められる。
1 * srcα + (1-srcα) * dstα = 0.5 + 0.5 = 1

Alpha合成を行う。
outC = 1 * srcC' + (1-srcα) * dstC'
= (0.5, 0.5, 0) + (0, 0, 0.5)
= (0.5, 0.5, 0.5)

複数合成の順序を変えても成り立つようにするため、最後にoutαで割る。
outC / outα = (0.5, 0.5, 0.5)

灰色になりました。


2. VG_BLEND_SRC_IN:

outαは以下の式で求められる。
dstα * srcα + 0 * dstα = 0.5 + 0 = 0.5

Alpha合成を行う。
outC = dstα * srcC' + 0 * dstC'
= (0.5, 0.5, 0) + (0, 0, 0)
= (0.5, 0.5, 0)

合成の順番を変えても成り立つようにするため、最後にoutαで割る。
outC / outα = (1.0, 1.0, 0)

黄色になりました。重ねた色そのものです。


3.VG_BLEND_MULTIPLY

outαは以下の式で求められる。(Src overと一緒)
1 * srcα + (1-srcα) * dstα = 0.5 + 0.5 = 1

outCは以下の式で求められる。
outC = srcC' * (1 - dstα) + dstC' * (1 - srcα) + srcC'*dstC'
= (0, 0, 0) + (0, 0, 0.5) + ( 0, 0, 0 ) // 第3項は内積
= (0, 0, 0.5)

暗い青になりました。乗算で暗くなる。


4.VG_BLEND_SCREEN

outαは以下の式で求められる。(Src overと一緒)
1 * srcα + (1-srcα) * dstα = 0.5 + 0.5 = 1

outCは以下の式で求められる。
outC = srcC' + dstC' - srcC'*dstC'
=(0.5, 0.5, 0) + (0, 0, 1) - (0, 0, 0)
=(0.5, 0.5, 1)

明るい青になりました。乗算の逆ですね。


5.VG_BLEND_DST_OVER

1の逆です。outαは以下の式で求められる。
(1-dstα) * srcα + 1 * dstα = 0 + 1 = 1

Alpha合成を行う。
outC = (1-dstα) * srcC' + 1 * dstC'
= (0, 0, 0) + (0, 0, 1)
= (0, 0, 1)

複数合成の順序を変えても成り立つようにするため、最後にoutαで割る。
outC / outα = (0, 0, 1)

やっぱり青です。


6.VG_BLEND_DARKEN/VG_BLEND_LIGHTEN

src overとdst overの暗い方/明るい方をとるとの事。
src over=(0.5, 0.5, 0.5)
dst over=(0, 0, 1)

ということで、
DARKEN=(0, 0, 0.5) 暗い青
LIGHTEN=(0.5, 0.5, 1)


7.VG_BLEND_ADDITIVE

単なる足し算です。1を超えたら1にします。

outα=min(srcα+dstα, 1)=min(1.5, 1)=1
outC=min(srcC'+dstC', 1)
=min((1.5, 1.5, 1), 1)
=(1, 1, 1)
最後にoutαで割りますが、結局白です。

画像で表示するとこんな感じ。
Imagination TechnologyのSDKを使用してます。