レイアウトエディタを使う
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の配置のほか、
画面の上部には以下のような設定が並んでいる。
作成したレイアウトは以下のようにして組み込める。ここでは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でドロイド君が出てこない
GoogleのAndroid 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を使用してます。