RSS

[Android] Contextの持ち方 (2)

 前回の日記で「ContextはApplicationを渡すのが基本(ドヤァ」なんてことを書いたが、それはちょっと言い過ぎで、やはり状況に応じたContextインスタンスを持つべきではある。
 つまり、Applicationじゃ困ることもあるということだ。

 例えば、三大Contextインスタンス(Activity、Service、Application…の3つと言えるだろう)の中でDialogを起動できるのはActivityだけである。DialogはWindowManagerやらを呼ぶためにコンストラクタでContextを要求する仕様になっているが、そこにServiceインスタンスを代入しても例外吐いて落ちるし、Applicationでもダメである。
 正直この仕様は納得がいかない。Dialogを起動出来るのがActivityならば最初から引数型をActivityクラスにするべきではないのか? まぁ、Dialogで利用するのはContextのメソッドであってActivity特有のメソッドは使わない、というなら確かにContextでいいのかもしれないが、だとすればなぜ他のContextで落ちるのか(Contextを要求してるのにContextを継承したクラスのオブジェクトを渡して落ちるとか、コンパイラさんの立場が無いのではないか。型安全はどこへいった。)。ちょっとよく調べてないのでわからないが、たとえActivityの派生型以外から起動出来る仕組みにしているのだとしても、DialogOwnerInterfaceでも定義して、そいつを実装したクラスのインスタンスを渡させるべきではないのか。
 まぁ私はプログラムの勉強を初めて日も浅いので、なにか見落としてる都合があるのかもしれないが…、実際紛らわしい仕様であることは確かだ。

 また他にも、こちらのサイトで挙げられているようにBroadcastReceiverなどをregistするときにApplicationを渡してしまうとメモリリークの原因になってしまう、ということもある。
  http://d.hatena.ne.jp/IchiRoku/20101230/1293717201
 
 Contextは「そのContext自身の生存範囲と利用側の都合が一致しているかどうか」を常に意識して扱わなければならない、ということだろう。アプリケーション全体で静的に持ちたい情報(複数画面で共有される情報など)はApplicationContextで。アクティビティと運命を共にすべき(完全にアクティビティ子飼いのビューなど)ならばActivityContextで。
 しかしそれを実践しようにもContextという抽象的な型でやりとりするのは紛らわしく思うのだが。

    public class Hoge {
        
        Application mApp;
        Activity mActivity;
        
        public Hoge(Activity activity){
            mActivity = activity;
            mApp = activity.getApplication();
        }
        
    }

 もういっそのこと、このような潔い持ち方をしたほうがいいんじゃなかろうか。
 ちょっと納得がいかないことが多いので継続調査!

 
コメントする

投稿者: : 2011/07/02 投稿先 Android, プログラム, Java

 

タグ: , , ,

[Android] Contextの持ち方~ApplicationContext

 Android開発では、Context型のオブジェクトを使い回すことがやたら多い。
 問題はActivity(もしくはService)の中で利用できるContext型のオブジェクトはActivity(Service)のインスタンス自身と、getApplicationContext() で取得できるApplicationのインスタンスの二種類があるということだ。

        // 例えばActivity内でトーストを表示するとき、以下2通りのContextを渡せる。
        Toast.makeText(this, "Activity", Toast.LENGTH_SHORT).show();
        Toast.makeText(getApplicationContext(), "Application", Toast.LENGTH_SHORT).show();

 このあたりについては各所でまとめられている。例えばこちらのブログなんかにうまくまとまっている。
  http://individualmemo.blog104.fc2.com/blog-entry-41.html
 また、こちらのサイトではわかりやすくActivityやApplicationの違いや役割が図解されている。
  http://magpad.jugem.jp/?eid=197

 で、どちらかというと「Applicationのほうを使いましょう」というのが基本だ。特に独自クラスなんかで半永久的にContextを保持しておくような場合はなおさらだ。先のサイトでも言及されているが、ActivityやServiceは常にkillされ破棄される可能性があり、変に保持しっぱなしにするとメモリーリークの原因になる他、いつのまにか実体がいなくなって例外を吐いたりなどなど。

 よって、独自クラスでContextを持つ必要があるときは大体getApplicationContext()の戻り値を渡すようにする。が、しかし、そういうルールの下で開発を進めていくと、ついつい「contextの実体はほとんどApplicationContextだ」と思い込んでしまう。実際問題として、たまーにActivityが渡されてくる場合もあるので注意が必要である。
 例えば、独自で実装した拡張ViewクラスをレイアウトXMLに定義した場合、独自Viewクラスのコンストラクタで渡されるcontextはsetContentViewしたActivityインスタンスだったりする。どういうことかというと、

public class RedButton extends Button {

    // XMLでlayout定義してsetContentViewでinflateしてもらうにはこのコンストラクタが必要くさい
    public RedButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setBackgroundColor(0xFFFF0000); //デフォルトで赤くする
    }

}

 こんな感じで新たに定義した独自ボタンクラスをレイアウトXMLで配置してアクティビティで呼び出した場合の上記contextの実体は呼び出したActivityオブジェクトが渡される。勿論、ActivityにセットしたViewなのだからこのRedButtonのインスタンスがActivityへの参照を保持しておくのは問題無い(アクティビティが死ねばボタンも消えるだろう)。しかしこのRedButtonクラスの中でクラス変数に代入…、いやそこまでじゃなくとも、別クラスに渡してしまうと厄介である。RedButtonのインスタンスとともに破棄されるインスタンス変数に渡すのなら問題ないのだが、Activityのライフサイクルを越えて保持される危険のあるオブジェクトに渡すのは危険である。
 Contextの実体に注意していればそのような渡し方はしないだろうが、普段からcontextにApplicationContextを使うようにして「context イコール ApplicationContextだ」という認識にはまってしまった場合、「ActivityのインスタンスをApplicationContextのつもりで保持してしまう」ということをうっかりやってしまう可能性がある。

 ということで、contextを貰ってきてそれを使い回す可能性があるのであれば、なるべくその実体がなんであるか明示して保持しておくようにしたい。例えば上記RedButtonクラスではActivityが渡って来るとわかっているのだから、

public class RedButton extends Button {

    private Context mAppContext;
    
    // XMLでlayout定義してsetContentViewでinflateしてもらうにはこのコンストラクタが必要くさい
    public RedButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setBackgroundColor(0xFFFF0000); //デフォルトで赤くする
        mAppContext = context.getApplicationContext();
    }

}

最初からこうしておけば後から追記する際もきちんと区別出来るだろう。貰ってきたcontextの実体がApplicationContextでもcontext.getApplicationContext()の戻り値は同じ(はず)なので、contextを保持したい場合は必ずこのメソッドを呼んでおくことで保証出来る。

 まぁこういったトラブル回避策は人それぞれ好みがあるのでなんともいえないけども。


追記:2011/7/1
 なんでもかんでもApplication渡せばいいってもんじゃないことを思い出したので、そのことについて次書きます。

 
1件のコメント

投稿者: : 2011/06/29 投稿先 Android, プログラム, Java

 

タグ: , , , ,

「とどけもの」解説メモ

 耳ロボPさんの名曲「とどけもの」 http://www.nicovideo.jp/watch/sm6917596
 この曲はジョークRFCであるRFC1149をパロったもので、インターネット電子メール送信に関わる要素をドラマティックに歌い上げられています。歌詞の中ではネットワーク技術の基礎的概念のメタファーがふんだんに用いられており、多くの理系視聴者がホイホイされてます。動画内でも各種解釈コメントが見られますが、自分なりに解釈(というより解説)をまとめてみようと思ったので、とりあえずはメモ程度。(最初は文章化しようとおもったが大変なことになりそうだった)。
 あまり突っ込みすぎた解釈はしていないつもりですが、明らかな間違いや、拾いきれてない表現はあるでしょう…。
 左が原曲歌詞、右が解説メモです。

ASCIIで したためて
後はよろしくと 手放す
天上人は気楽だと
下界のものは 皆思う

5階には老執事
事務処理はおまかせあれ と
作法に基づく 身のこなし
あせるな まずは挨拶から

ああ 彼方から あの声
ゆく先々 嵐の路も あるよ

4階の飼育士は
鳥たちに餌を与える
旅立ちの日が訪れた
25の港をめざせ

ああ 彼方から あの声
アドレスなら 頭の中にあるよ

運べるだけの紙片をもち
この 3階の窓から
3次元エーテル空間へ
いざ 羽広げ ダイビング

いそがしい 僕らの
代わりに 風を切って
彼の地を 目指して
高く 舞い上がれ

ああ 彼方から また声
この世界の 全体図などないよ

無数の鳥が 橋を 壁を 越え
ゲートを くぐってゆく
果ては ある
だが 地図など持たぬゆえ
迷うこともあろう

幾羽は 疲れて
地に 落ちてゆくだろう
それでも ふたたび
舞い上がるだろう

いそがしい 僕らの
代わりに 風を切って
目指した港の 扉が開いた

 電子メール送信 / SMTP / RFC 5321 / US-ASCII使用
 非ASCII ⇒ MINEで符号化
 天上人 = 人間、エディタ、メーラー
 下界のもの = SMTP通信を担う下のレイヤ

 5階 = OSI参照モデル / セッション層
 老執事 = SMTP-Client? or RFC1149実装実験の人
 事務処理/作法 = SMTPによるやりとり
 まずは挨拶から = HELO
 (TCP接続要求に対し返答が来たあと最初にするのはHELO)

 彼方からあの声 = 宛先サーバからのレスポンス
 嵐の路 = ネットワーク障害 / パケロスの可能性は常に

 4階 = OSI参照モデル / トランスポート層
 飼育士 = ? / RFC1149実装実験の飼育士
 (TCPヘッダの付加 = 餌?)
 25の港 = SMTPのポートはTCPの25

 IPアドレスはIPヘッダに
 メールアドレスはメールヘッダに

 データはTCPセグメント/IPパケットに分割
 前者はMSSオプションで指定されたサイズだし、
 後者は64kbytes弱が限度 ⇒ 運べるだけ
 3階の窓 = OSI参照モデル / ネットワーク層
 エーテル空間 = イーサネット だが
 「3次元エーテル空間」はRFC1149実装実験におおける「現実の空間」
 羽広げ = 鳥 = 伝書鳩 = 生体パケット ⇔ IPパケット

 彼の地 = 宛先サーバ

 IPパケットは中継されルーティング(経路制御)され送られる
 全体案内図など無い

 橋 = ブリッジ / 中継器
 壁 = ファイヤーウォール
 ゲート = ゲートウェイ
 果てはある = 解釈多 / 目的地が存在する・しない
  / エンドポイント? / 終端? / ホップ数???
 IPパケットそのものは必ず届くことは保証されない ⇒ ので迷う

 ネットワークの状況によりパケットロスするが
 TCP通信なのでパケット再送される

 そして宛先サーバーの25の港はIPパケット⇒TCPセグメントを受信する

 
コメントする

投稿者: : 2011/06/22 投稿先 ネタ, 科学, 音楽

 

タグ: , , , , , , , ,

[Java] 可変長引数にnull

 Googleで検索するとわんさか解説が出て来ますが面白い話題だなと思ったので自分でもまとめます。

 参照型の可変長引数にそのままnullリテラルを代入しようとするとコンパイラさんに怒られます(警告)。というのも、可変長引数は実際メソッドローカルな配列になるわけですが
 「配列の参照がnullなの?それとも要素の参照がnullなの?わけがわからないよ。」
と、コンパイラさんは言いたいわけです。いやはや全くもってその通り。

    public static void main(String[] args) {
        // 怒られるパターン
        handleVarArgs(null);
    }

    public static void handleVarArgs(String... params){
        // paramsに対する処理など
    }

 正しい代入を行って警告を消す為には「キャストして型を明示する」必要があります。
  (a) 引数型の配列型にキャスト
    上記で言えばString[]型だと明示することでparamsの参照がnullになる。
  (b) 引数型にキャスト
    上記で言えばString型だと明示することでparams[0]の参照がnullになる。paramsという配列は作られる。

 ここで分かりやすく整理するため、配列型の引数での表現と比較してみることにしましょう。

    public static void main(String[] args) {
        
        // 可変長引数と配列引数の等価っぽい表現
        
        /** (a) 引数型の配列型にキャスト */
        handleVarArgs((String[]) null);  // 配列型にキャストすると、
        handleArray(null);               // 配列にnullを代入したのと同じ
        
        /** (b) 引数型にキャスト */
        handleVarArgs((String) null);    // 引数型にキャストすると、
        handleArray(new String[]{null}); // null要素の配列を作成して代入するのと同じ
        
        /** (c) 引数無指定 (おまけ) */
        handleVarArgs();                 // 実引数を何も指定しないと、
        handleArray(new String[]{});     // 要素数0の配列を作成して代入するのと同じ

    }
    
    public static void handleVarArgs(String... params){
        // 実装
    }
    
    public static void handleArray(String[] params){
        // 実装
    }

 というわけです。
 可変長引数って便利で好きなので良く使うのですが、上記の振る舞いを考えるとほいほい使うのもどうかなという気がしてきます。例えば、上記の例では実装は省略しましたが、そこで int i = params.length なんて処理を書いたりした場合、(a)ではNullPointerExceptionなりますが、(b)ではiには1が代入されます(ついでに言えば(c)では0が代入される)。当然の振る舞いではありますが、ミスの要因になる可能性があるというか…(特にチーム開発に於いて)。引数を配列型にしておけば、配列を作成する手間はありますが中で扱われる配列の形が明確に見えるので比較的安全かもしれません。

 まぁ、そのメソッドの引数は配列であるべきなのか、可変長引数であるべきなのか、きっちり考えた上で決めましょうという話ですね(オーバーロードできないし)。

追記: 値型の可変長引数
 以上は、参照型の可変長引数でしたが、値型の可変長引数へのnull代入はキャストで型を明示する必要がありません。値型変数はnullリテラルを受け付けないわけですから、nullを代入すると問答無用で「配列の参照がnull」と判断されます。(a)のパターンですね。勿論、敢えて配列型へのキャストを書いても問題ないでしょう。

 
コメントする

投稿者: : 2011/06/15 投稿先 プログラム, Java

 

タグ: ,

[Java] 同サイズの長方形をN個敷き詰め可能な最小の正方形

 ※長方形の回転は考えない

 [Android] テクスチャ用正方形画像を合成 (2)
の続きだけど、またしても純粋にアルゴリズムの話なので、とりあえずJavaという接頭辞をつけた。

 上記記事に沿って画像を合成を考えると色々なメソッドを作り出していく必要があるのだけど、そのうちの1つの話。
 最初は、縦と横の比率から一般解を求めることが出来るだろう、と考えていたのだが、どうにも思いつかなかった…。おかしい、絶対一般解があるはず…。と頭を捻ったのだが、どうもやはり自分に数学的センスは無いらしく、思いつかない。簡単な解法はあるのかなぁ。

 しかし思いつかないとはいえ諦めるわけにはいかないので、ここはプログラム手法的に解く。要するに実際に並べるシミュレーションを行えばいいのだ。例えば「20cm×25cmという長方形を8個並べるのに必要な最小の正方形領域はいくつか?」という問題に対しては、
  (a) とりあえず短辺の方向に並べて行く
  (b) 3つ目を並べるときは長辺方向に拡張したほうが得である [40cm×50cmの領域が出来る]
  (c) 5つ目を並べるときは今度は短辺方向に拡張したほうが得 [60cm×50cmの領域が出来る]
  (d) 7つ目を並べるときは長辺方向に拡張したほうが得 [60cm×75cmの領域が出来る]
  (e) 8つ目は確保した領域のどこかに置く
  (f) 以上で確保した領域をラップするのに必要な正方形領域は 75cm×75cm
 …例えば(d)の時点で短辺方向に拡張してしまうと最終的に必要な正方形は80cm×80cmになってしまい、損である。まぁ文章で説明するとややこしいが、実際に並べてみればわかりやすい。

 以下で貼り付けるコードはこの画像のようなイメージの元、書いた。
 
 ちょっとこの図だと、lengthが固定でその中に敷き詰める数を求める問題っぽいが、今回のアルゴリズムは並べたい個数を与えて最小のlengthを求める問題である。

    /**
     * 同じサイズの長方形を回転せずにタイル状にnum個詰め込める最小の正方形の一辺の長さを計算する
     * @param unitWidth 並べる長方形の幅
     * @param unitHeight 並べる長方形の高さ
     * @param num 並べたい数
     * @return 必要な最小の正方形の一辺の長さ
     */
    public static int calcFillableSquare(int unitWidth,int unitHeight,int num){
        
        //numが不正なら0を返す
        if(num < 1){
            return 0;
        }
        
        //ユニットの長辺と短辺を判断する
        int longSide = Math.max(unitWidth, unitHeight);
        int shortSide = Math.min(unitWidth,unitHeight);
        
        //長辺方向に並べる数と短辺方向に並べる数
        int i = 1; //並べ可能な長方形の総数
        int l = 1; //長辺方向に並べる数
        int s = 1; //短辺方向に並べる数
        while(i<num){
            // 次の長辺方向に数を増やした時の長さよりも、
            // 次に短辺方向に増やした時の長さが長くならない限り、
            // 短辺を増やす。この関係が逆転した場合のみ長辺を増やす。
            if((s+1)*shortSide <= (l+1)*longSide){
                s++;
            } else {
                l++;
            }
            i = s*l; //以上の処理までで並べることが出来る長方形の最大数をカウンターに返す
        }
        
        //必要な一辺の長さを返す   
        return Math.max(s*shortSide, l*longSide);
        
    }

 もうちょっと綺麗なアルゴリズムがありそうだけど、こんなもんだろうか。ちょっとややこしいけどやっぱりアルゴリズム入門編という感じがある(笑)。ともかくこれで求められていると思う。強引なので計算量がやや多いが、そんな何万個も長方形を並べることは無いだろうから、コレでも良いだろう。

<ちなみに>
 上記のアルゴリズムで20*45の長方形に対して、N=1 から N=1000までの正方形のサイズをプロットしたら以下のようなグラフになった。

 エクセルのツールで簡単に近似したところ、みての通り、√Nに近い関数でかなり綺麗にフィット出来ている…(ずれているのは明らかに離散的な値を連続的な関数でフィットしてるから仕方ない)。うーんやっぱり絶対一般解あるよなぁこれ。

※追記
 ってよく考えたらオーダーが√Nになるのは当たり前。
 問題はそれにつく係数と、このステップ関数を如何に表現するかであって…やっぱり難しいような

 
1件のコメント

投稿者: : 2011/06/12 投稿先 プログラム, Java

 

タグ: , ,

[Android] テクスチャ用正方形画像を合成 (2)

以下の記事の続きである。今回は問題の整理だけでソース無し。
 [Java] ある整数よりも大きい最小の2のべき乗を計算
 [Android] テクスチャ用正方形画像を合成 (1)

 前回の記事で、テクスチャ用の正方形画像を合成することが出来た。しかし正方形の一辺の大きさが2のべき乗であるという制約上、どうしても無駄な領域が生じてしまう。そこで、なるべくうまく領域を使うために1つの大きな正方形領域にテクスチャ化したい画像を並べたものを合成することが望ましいだろう。これはグラフィックメモリの効率的にも、また「テクスチャを作成する処理は重い」という理由からもやっておくべき処理だ。

 ということで特定の正方形の中に、長方形をなるべく効率よく敷き詰めるアルゴリズムを考えるわけだけど、
   「任意の大きさの多数の長方形を正方形の中になるべく密に充填する問題
…って、ちょっとどころじゃなく難しい。こういう問題を専門的にやってる分野もあるだろうから、多分うまい解は既に考えられているんじゃないかと思うが、軽くググった程度では目的に沿うような解を見つけることが出来なかった。

 そもそもなぜこのアルゴリズムが必要になるのか?そして既存のグラフィックス屋さんはどう解決しているのか?

 後者については、通常、3Dグラフィックスのテクスチャは「あらかじめ用意したものを使う」ので問題にならない(のだと思っている)。正方形になるにしろ長方形になるにしろ、ひとつなぎの大きな画像領域の中に、使用するイメージを並べたものを用意し、それをテクスチャとして読み込み、テクスチャ座標を指定してポリゴンにマッピングしていくのが普通だ。3Dに限らず効率的に画像を処理する場合は割と常識的なテクニックで、ゲーム作成をしたり、RPGツクールのようなゲームをやったことある人は、どのような画像リソースを用意するのか想像出来ると思う。

 では今回なぜこの手法を必要としているのかというと、「アプリケーションのユーザーが用意した画像を読み込めるようにする為」だ。まぁこれが本当に3Dポリゴンに貼り付けるテクスチャ画像を要求するのであれば、最初からテクスチャ用の画像を用意してもらうのがスジだろうが、OpenGLを用いた2Dライクなユーザーインターフェイスの作成を目的とした場合、例えばユーザーに用意させたい画像というのは「オリジナルのボタン画像」とか「オリジナルのアイコン画像」とかそういう類のものになる。オリジナルのアイコンを読み込ませるのに、わざわざテクスチャマッピングを意識した画像を用意させるわけにもいくまい。
 そういうわけで、ユーザーが用意した複数の(例えばアイコン)画像をテクスチャ化することになるわけだが、なんとかしてテクスチャ化に適した画像に加工しなきゃだめだよねという話なのであった。ああ道のりは長い。
 しかしそこで本当に任意の画像を自由に読み込ませる必要があるだろうか?アプリケーションの制約というものがあるはずだ。例えば「オリジナルのアイコン」を読み込ませるとして、2000px*2000pxのような巨大画像や、100px*4pxのような細長い画像を許容するものだろうか?多分、アイコンとして適した画像のサイズがあるはず。そう考えると、「指定したサイズの画像」もしくは「指定したサイズ以内の画像」しか使えませんよ、という制約があって良い。というか多くのアプリケーションがそういう方式を採用している。

 というわけで、画像合成の方針としては
  「同じ大きさの多数の長方形画像をタイル状に並べたなるべく小さな正方形画像を合成する
というものを目指すことにする。イメージとしては以下のような感じ。

 アプリケーションの制約としては、同じサイズの画像を用意させることにしてもいいが、「用意した画像は全て長辺が100pxまで縮小されます」みたいなことも可能だろう。前回の記事で紹介したラッピング合成の手法を使えば、ラッピングして同じサイズの画像にした上で並べればよい(そうすると無駄は増えてしまうが)。
 こんなところを妥協点として、画像合成アルゴリズムについて進めてみようと思う。

 
1件のコメント

投稿者: : 2011/06/11 投稿先 Android, プログラム, Java

 

タグ: , , , , ,

[MMD] MMDを弄ってみた

 最近、開発終了宣言が出されてしまった3Dアニメーション作成ツールMMD(MikuMikuDance)。ちょっといろんな目的があって弄ってみた。3Dグラフィックスの勉強にもなりそうだし。

 とりあえずインストール。
 公式サイトVPVP様より、MikuMikuDance(DirectX9 Ver)(最新版)をDL。直接展開して配置。んでまぁEXEを起動するも以下のようなエラー。ちなみにOSはWindows 7 Enterprise 64bit。
 

 まぁ事前に調べておいたとおりなので、MS公式からランタイムパッケージをDLしてインストール。
 DirectX エンド ユーザー ランタイム Web インストーラ

 問題無く起動成功。

 が、本当に大変なのはここから先なわけで。
 試しに人体モデルのボーンとかを弄ってみるものの、なかなかうまくいかない。操作は結構直感的(3D-CADのUIっぽいらしい)なのだけど、当然操作するパラメータが膨大なので大変。慣れないもんだから、初音ミクの手や足がものすごい方向に曲がったり捻れたり…これは…ちょっとコワイ。
 難しい概念とかは無いものの、基礎がおろそかになってる気がしたので、
  MMDでアニメーションを作ろう!!~前編~
という動画でお勉強。実践的で勉強になる。まずは前編だけで十分。

 …ということで数時間格闘し、こんな感じのものを作ることに成功。(Y軸が表示されちゃってるのはご愛敬)

 シチュエーションは気にしてはいけない。大学講堂っぽいところで、なんかポーズをとる健音テイ。たったこれだけのものを作るのもなかなか大変だった。けど、基本は少しずつ理解出来てきた気がする。…あとはどれだけ省エネでモーションを作成出来るか。まぁMMD動画を作りたいわけでは無いので、そんなに拘りはしないけども。

 なんとも奥の深いソフト。慣れるまで相当の努力が必要そうです。

追記:
 テイのモデルはこちらの動画で配布されていたもの
  【MMD-UTAU】テイ&テトでトリノコシティ【髪テカテイ配布】
 背景の講堂はこのへんから
  http://www6.atwiki.jp/vpvpwiki/pages/28.html#id_4ba451f9

 
コメントする

投稿者: : 2011/06/05 投稿先 MMD, 日記

 

タグ: , ,

[Android] テクスチャ用正方形画像を合成 (1)

 今回も比較的基本的な話。

 5月26日の記事で書いたように、OpenGL ESでは原則的に非正方形テクスチャは使えず、正方形でも一辺の長さが2のべき乗である必要がある。じゃあテクスチャ用画像を合成で作成してしまおうという話だった。前回で2のべき乗に関する計算をするメソッドを作成したので、今回はそれを使って実際に画像合成のサンプルを作成してみる。

 今回使ってみる画像はコイツ。
 

 実際にプロパティでも見ていただくとわかるが、この画像のサイズは240px×149px。なので256px×256pxの正方形にくるんでやれば良いことになる。画像の合成を行うコードはこんな感じになる。


    public Bitmap makeTexturableBmp(Resources res, int resId){
        
        //画像サイズに応じてビットマップ作成
        Bitmap org = BitmapFactory.decodeResource(res, resId);
        Bitmap ret = null;
        if(org!=null){
            int w = org.getWidth();
            int h = org.getHeight();
            if(w==h && MathUtil.isPowerOfTwo(w)){
                //正方形で一辺が2のべき乗ピクセルならそのまま使う
                ret = org;
            } else {
                //ダメなら2のべき乗正方形で覆ったビットマップを作成する
                //w*hの画像を覆える最小の2のべき乗正方形を算出
                int len = MathUtil.padToPowerOfTwo(w,h);  
                Bitmap wrapper = Bitmap.createBitmap(len, len, Bitmap.Config.ARGB_8888);
                Canvas offScreen = new Canvas(wrapper);
                offScreen.drawColor(0x99990000); // ← 確認のために色を塗る
                offScreen.drawBitmap(org, 0f, 0f, null);
                ret = wrapper;
                org.recycle(); //ちゃんと消しておく
            }
        }
        
        return ret;
        
    }

 MathUtilというクラスは5月26日の記事で載せた静的メソッドを集めたクラスである。条件に合う正方形ビットマップを作成し、Canvasオブジェクトをオフスクリーンとして合成を行って返すだけ。面倒くさいのは条件分岐のところなのだが、MathUtilを作っておいたのでさくっと書けた。あとはこのメソッドにリソースを食わせてあげればいい。

        ImageView img = (ImageView) findViewById(R.id.img);
        img.setImageBitmap(makeTexturableBmp(getResources(),R.drawable.qbsample));

 今回はアクティビティのonCreateで適当に描画して確かめる。実機(Xperia arc)の実行結果SSを撮ってみた。

 ちゃんと256の正方形でくるまれた画像になっている。実際は色を塗らずに作成し、このビットマップをまるまるテクスチャとして登録した後、クリッピングすればよい。テクスチャ用に作ったのにテクスチャとして確認してないのは、OpenGLのコードを書くと長くなってしまうので。

 さて、ここまでだらだら書いておいてナンだが、ぶっちゃけこの方法はあまり効率がよくない
 無駄が多いのは明らかだろう。例えばQB画像の横幅が257pxだっただけで、ラッパーの正方形は512px四方になってしまうのである。空白の部分にメモリを食うのは無駄だ(多分、そんな都合良い最適化とか行われないだろうし?)。ただでさえメモリの少ないAndroidでそんな無駄を許していいだろうか、まぁ状況次第だろうか。
 そうなるともう少し広大な正方形を用意して、複数の画像をなるべく隙間無くマージしよう、という話になる。しかしこれは難問だ。今回のようにあらかじめサイズが分かっている画像リソースをマージするならうまいパッキング方法を自分で考えられるが、例えば、任意に指定された画像ファイルをマージするとなると……数学的な難問になってくる。
 まぁ本当に任意のサイズの長方形を正方形にパッキングするアルゴリズムというのはあまりに大変なので、そのへんを上手く避けたソリューションを考えなければならない。次回はそんな記事を書く…かもしれない。

 
1件のコメント

投稿者: : 2011/05/31 投稿先 Android, プログラム, Java

 

タグ:

日比谷オクトーバーフェスト2011 part3

 そういや今日は最終日。結構雨が激しいがやっているのだろうか。
 で、昨日また行ってきた。三回目。休日出勤帰りの同僚と合流して、19時半頃現地へ。
 雨が降っているせいで相当空いていた。降っているといっても小雨だったのでステージ前で盛り上がってる連中は気にしていない様子。っていうか雨で濡れてるのか、ビールで濡れているのかわかりゃしない。


 現地で別の友人とも合流することで席を確保。が…そこはステージ前テントの最前列…結果的に三回目にして一番盛り上がることになった。
 この写真はステージ前のモッシュピット騒ぎに参加したときもの。まぁこんな中でビールもってカメラをしっかりホールド出来るわけもなくブレブレだけど、どんな状況かは伝わりやすいだろう。量の入ったグラスをもって参加するものではなかった。危ない危ない。

 そういうわけで以下飲んだビール。全部じゃないけど。

 えーと、左から「アインベッカーの何か」「ホフブロイのシュヴァルツヴァイス」「シュパーテンのオプティメータ」。アインベッカーはなぜかいつも列が空いてた記憶があるのだけど不人気だったのかなこれ?まあ味は普通な感じ。ホフブロイは黒白ってどういうこった。ちょっとなんかスパイシーな感じがした気がする。オプティメータは元々好きなのだけど、3回目にしてやっと飲めた。やっぱり自分は黒いのが好きだと再確認。
 さて、その後、落ち着いたところで腹も満たそうということで、同僚と二次会に。
 場所は、実は木曜日も二次会で行った、有楽町高架下の宮崎地鶏のお店。多分「なれる!SE」の4巻で出てきた店もここがモデルだと思うんだけど、オススメ。ちょっとお高いけど、やっぱうまいもんには金を惜しんではいけないのだ。

地鶏!
地鶏!地鶏!
 ここで日本酒を3合ちょいくらい飲んだのだけど…流石に少し飲み過ぎたのか家に帰りついた頃にはべろんべろんになっていた。いやほんとに日本酒ってのは良く回る。

 ということで今度こそ今年のは最終参加。散財した!
 7月には代々木でまたあるけどどうしたものかね。

 
コメントする

投稿者: : 2011/05/29 投稿先 , 日記

 

タグ: , , , ,

日比谷オクトーバーフェスト2011 part2

 前回の日記では一人だったが、昨日は友人と行ってきた。
 まぁ詳しい話はもういいだろう。飲んで騒いできたわけだ。


エルディンガーの黒いの。
シュバルツビアって書いて売ってるけど要するに「黒ビール」じゃねーか。デュンケルもそうだったがエルディンガーはさっぱりしてる感。ちょっと1日経つと味が思い出せない…。

すんげーハーブくさいスピリッツ。
俺は好みだが癖がありまくるので人にはオススメしない。実際は飲めよ飲めよとネタ的にすすめたが(何
500円。ちょっと高いが、翠星石みたいな格好をしたお姉ちゃんが売りに来たので思わず買った。

フレンスブルガーの白いの。
もはやドイツビールとしては定番ですな。甘めです。
 そういや、会場で神主っぽい人を見かけた。いやあれはどう見ても神主だった。噴水脇のいい席に座っておりました。まぁもちろん面識はないので遠巻きからジロジロみただけですがw。東京ではこういう面白いこともあるんだなー。
 あとは別の友人ともばったり(?)会った。彼女連れだった。もげてしまえ。

 土曜日も行く予定だったけど、予報雨だし、相手も忙しそうだから多分行かないと思う。まぁ今後もこういう祭りは積極的に参加していきたい。飲みのお誘いいつでも待ってます。

 
コメントする

投稿者: : 2011/05/27 投稿先 , 日記

 

タグ: , , , ,