C#は電気羊の夢を見るか?(引っ越し中)

dtiブログが閉鎖とのことでhttp://tanocs.blog.fc2.com/へ引っ越します。

CsharpSQLiteの問題点

C#で実装し直された完全マネージッドなSQLite
http://code.google.com/p/csharp-sqlite/

このCsharpSQLiteは特定の文字列がクエリに含まれていると実行できないバグがある

問題はSqlite3クラスのクエリチェックメソッド『sqlite3GetToken』内にて発生していた
原因はString[]からByteにキャストして、ヌル文字を判定している箇所にて、
string[]に2バイト文字が入った場合、前半1バイト分が情報落ちする。
そのため、下1バイトが'00'の文字でヌル文字と判断されるため、クエリが通らなくなる。

尚、その条件に当てはまるのは以下の16文字
∀、─、一、稀、紀、儀、言、最、蔀、需、退、刀、謀、掘、耀、椀

以上の文字を含むクエリは以下の例外で終了してしまうはずです。
Community.CsharpSqlite.SQLiteClient.SqliteSyntaxException (0x80004005): unrecognized token '対象文字


修正はわりと単純で
Community.CsharpSqliteプロジェクト内の
complete.csとtokenize.csを修正すれば良い

以下は「sqlite_3_7_7_1_71」を元にした場合の修正方法
(尚、12月19日コミット分でも同様の方法で修正できます)

■complete.cs内
◇44行〜

static bool IdChar( u8 C )
{
return ( sqlite3CtypeMap[(char)C] & 0x46 ) != 0;
}

≡変更≡

static bool IdChar(char C)
{
return (sqlite3CtypeMap[C] & 0x46) != 0;
}



◇244行〜

if ( IdChar( (u8)zSql[zIdx] ) )
{
/* Keywords and unquoted identifiers */
int nId;
for ( nId = 1; ( zIdx + nId ) < zSql.Length && IdChar( (u8)zSql[zIdx + nId] ); nId++ )

≡変更≡

if (IdChar(zSql[zIdx]))
{
/* Keywords and unquoted identifiers */
int nId;
for (nId = 1; (zIdx + nId) < zSql.Length && IdChar(zSql[zIdx + nId]); nId++)


■tokenize.cs
◇129行
byte c = 0;
≡変更≡
char c = '¥0'; //¥を半角して下さい


◇201行
c = 0;
≡変更≡
c = '¥0'; //¥を半角して下さい

◇"(byte)z" を "z" に置換



最後に、情けない話ですが、
どなたか、本家のコミュニティに、この事を伝えられる方がいたら伝えてください。
英語とか、読んで雰囲気を感じるのが精一杯なんですorz


追記:2012/12/22
と思ったら既に本家のコミュニティで4月には、わかっていた問題だったようで、
issueとして対策が載っておりMileStone3.7.11として登録済みでした。

尚、それを参考に修正方法を、キャストしない方式に修正しました。

http://code.google.com/p/csharp-sqlite/issues/detail?id=151
このエントリーをはてなブックマークに追加
LINEで送る

ComboBoxへDictionaryを関連付ける

ComboBoxへDictionaryを関連付けたいだけなのだが、
情報が散らばっていて、分かりにくかったので、自分なりに、こうしたよというメモ。



ミソは以下の2つ
・BindingSourceでバインドする
・イベント中ではKeyValuePairへキャストする

追加はこんな感じ


選択はこんな感じ
comboBox1.SelectedValue = "b";

または、こんな感じ
comboBox1.SelectedIndex = 1;

バインドを強制的に外す



もっとスマートな実装方法がある場合は、コメントで指摘していただけると嬉しいです。


2012/12/17 修正
・クリア方法が無駄に小難しく書かれていたのを修正
・ドロップダウンの長さが残ってしまう問題を修正
・クリア後、例外が出てしまう問題を修正
・選択方法を追記
このエントリーをはてなブックマークに追加
LINEで送る

C#で、ネイティブなEXEを作成する

通常であればC#で開発したアプリケーションは.Net Frameworkが
インストールされた端末か、Monoが有る環境でしか実行できない。

しかし、Monoを使用してmkbundleというコマンドにてネイティブ化を行うことで
Monoや.Net Frameworkのインストールがされていない端末でも、
インストール作業なしで実行を行うことが可能になります。


この手法、海外のサイトを調べてみるとcygwinを使用した方法が主流ですが、
根っからの窓っ子の自分にはどうもとっつきにくい。
調べていくと、cygwinを使わずとも出来ることが解ったので、cygwinは抜きの手順です。


尚、出来上がるexeの実績については、SharpDXを使い1000本ほど配布を行いましたが、
WinXP、Vista、7にて32、64bitを問わず、実行できなかったという回答をもらっていないことから、
割と多くの端末で動作しているものと思われます。



記事を起こした時点での動作確認は以下のバージョンにて行なっています
・[Mono] 2.10.9
・[gcc for Windows] 4.7.2
・[GNU utilities for Win32] Last Update:2011-04-05


以下に長々と書いていますが、スムーズに行けば
準備3ステップ、実行3ステップの単純なものです。

◆準備
Monoをインストール
gccコンパイラをインストール
GNU utilities for Win32を配置

◆実行
mkbundleを実行
⊇侏莨紊った[temp.c]を編集
コンパイルを行う


■準備編
Monoインストーラをダウンロードする[mono-2.10.9-gtksharp-2.12.11-win32-0.exe]
http://www.mono-project.com/Main_Page

Mono for Windows, Gtk#, and XSPをダウンロードして、インストールしてください。
この時、インストールしたフォルダはコマンド等で頻繁に使用しますので、覚えておいてください。

★これ以下では、例として[C:Mono]にインストールを行ったものとして記事を書きますので、
別の場所に保存した方は適宜読み替えてください。



Win32の『32bit版』のgccコンパイラをインストールする[gcc-4.7.2-32.exe]
http://www.equation.com/servlet/equation.cmd?fa=fortran

!!64bit版のOSであっても、必ず32bit版をインストールしてください!!

☆ユーザー名が日本語の方はフォルダ名が化けているので修正してください。
 この時、日本語が含まれていないほうが望ましいと思われます。



GNU utilities for Win32を配置する[UnxUtils.zip]
http://sourceforge.net/projects/unxutils/
[UnxUtils.zip]を解凍し中に入っている[sh.exe]を[c:monobin]に配置する

☆後述しますが、このファイルは今回の目的にはかなりリッチなモノです。
また、実行時ウィンドウを小さくするバグを持っていて、最適とは言いがたいです。
詳細は[[脱線]]を御覧ください。



ず撞動して準備完了
!!環境変数を反映させるため手動での再起動が必要です!!


[[脱線開始]]
ここで必要なのは[sh.exe]という名前で[as -o temp.o temp.s]を実行してくれるアセンブリです。

.Netアセンブリのexeでも問題なく動作しますので、良く解らない物を使いたくないという人は、
適当な[HelloWorld.exe]を[sh.exe]にリネームして配置してしまうのも手です。
この場合mkbundle終了後cmdより[as -o temp.o temp.s]を手動で実行する必要があります。

ベストなのは、HelloWorldではなく[as -o temp.o temp.s]をキックするアセンブリであるのは
言うまでもありません。

さらに、mkbundleはオープンソースになっているため、
自作にて[sh.exe]を使わないようにカスタムする手もあります(後述)
[[脱線終了]]




■実行編
mkbundleを実行してgccアセンブラソースとmonoオブジェクトを取得する
【1.スタートメニューから「Mono-2.10.9 Command Prompt」を実行】


【2.ネイティブ化したい実行ファイルのあるフォルダに移動する】


【3.mkbundleを実行する】
・DLLなし
 mkbundle -c -o temp.c --deps --keeptemp hoge.exe

・DLLあり
 mkbundle -c -o temp.c --deps --keeptemp hoge.exe foo.dll bar.dll

・SharpDXを使う場合の具体例
mkbundle -c -o temp.c --deps --keeptemp Sample.exe SharpDX.Direct3D9.dll SharpDX.dll


!!ウィンドウが小さくなった後も引き続き[as -o temp.o temp.s]が実行されるので、
ウィンドウの×で終了しないでください!!

☆GNU utilities for Win32を使用するとウィンドウが小さくなってしまい、
 mkbundleのログが見えなくなってしまいます。

☆[as -o temp.o temp.s]は一緒に入れ込むdll次第では長時間となる場合があります

☆ログメッセージの
warning: pointer targets in passing argument 2 of 'mono_register_co
nfig_for_assembly' differ in signedness [-Wpointer-sign]
については後述。


【4.[exit]コマンドで終了】
ウィンドウが小さくなっていて見づらいですが、
[as -o temp.o temp.s]の実行が終了して入力が可能になるのを待って入力してください。


【上手くいかない時は】
☆SharpDX等インターネットからダウンロードしたdllなどのアセンブリを使用する場合、ブロックの解除が必要

☆署名有りDLLはダメなことがあるので、署名なしのものを利用してください。
 ここで通ってしまうこともありますが、後々問題を引き起こすので、署名なしのものを使ってください。

☆mkbundle実行時、exeの作成時と違うバージョンのdllを同梱しようとするとFileNotFoundになるので注意
 ソリューションをバッチビルドでリビルトしてやれば直る



⊇侏莨紊った[temp.c]を編集
#ifdef _WIN32
#include
#endif

//【以下2行を追加】
#include<direct.h> //<>を半角にしてください
#undef _WIN32

/////////////////////////////////////////////////

int main (int argc, char* argv[])
{

//【以下5行を追加】
char Path[4];
if(0 != GetModuleFileName( NULL, Path, 4)) {
Path[3] = '¥0'; //¥を半角にしてください
chdir(Path);
}


"#undef _WIN32"を書かないとコンパイル時にエラーが出て先に進めない
他は日本語を含むパスから実行するときにmono-2.0.dllが見つかるようになる魔法の呪文



コンパイルを行う
gcc -g -o AssemblyName -Wall temp.c -mms-bitfields -mwindows -IC:/Mono/include/mono-2.0 -mms-bitfields -mwindows -LC:/Mono/lib -lmono-2.0 -lws2_32 -lpsapi -lole32 -lwinmm -loleaut32 -ladvapi32 -lversion temp.o

!!以下の引数についてMONOのインストールディレクトリに適宜を記述を変更すること!!
-IC:/Mono/include/mono-2.0
-LC:/Mono/lib


☆「アクセスが拒否されました」とかメッセージが出る場合
cygwinがすでにインストールとかされてて、インストールしたgccより優先されてしまっているので、
環境変数の順番変えてインストールしたwin32のgccが実行されるようにしてくりゃれ。


☆cannot find -lmono-2.0とかってメッセージが出てる場合
このメッセージが出力されるのは64bit版gccをインストールしているから
Mono-2.0は32bitアセンブリのため、読み込むことが出来ずエラーメッセージが出力される。

解決するにはインストール時に登録されたgccの環境変数を手動で消して、
インストールしたフォルダを消して32bit版を再インストールしてください。

[蛇足]64bit版で実行しても速度に大きな改善はないので、面倒の少ない32bit版で行うのが良いと思う


☆最適化オプションについて
ある程度、最適化オプションを自由に設定できるが、思ったほど効果が上がらなかった。
なにか良いオプションを知っている方がいたら、ご一報ください。



exeが出力されて完成
出来上がったexeと[Mono-2.0.dll]を同じフォルダにいれれば、.Netのない環境でも実行できる。

配布時、exeのみとする方法もありますが
『mkbundle実行時に--staticフラグ付けて静的リンクしたら、お前のプログラムもLGPLだかんね』
http://www.mono-project.com/Mono:Runtime

とのことなので、おとなしく[Mono-2.0.dll]を外に出しておくのが無難だと思います。
「LGPL?上等!逆アセンブルなんて怖くねーぜッ!」って方はご自由に。



★★★★★実行がうまくできない時は★★★★★
=SharpDXでエラーが出る時は=
・最新版のDX入れてね☆(ゝω・)
http://www.microsoft.com/ja-jp/download/details.aspx?id=35


=実行しても、うんともすんとも言わないとき=
・同梱したdllのバージョンが、アセンブリ生成時と違ってたりする事があるのでリビルトを試す

・署名がついてるdllが混ざっていないか確認する

経験則で理解できてはいないけどmkbundle実行時、アセンブリの記述順で良くなったりダメになったりする事がある。
コンパイルは通ってexeは出来るけど、実行時うんともすんとも言わないパターンなので容赦ならない。


=署名関係について=
署名付きのdllしか提供されていない場合Mono付属の[sn.exe]で署名の上書きが出来るらしいが、権利的に怪しい。
出来る事ならソースコードをダウンロードして、自分で署名なしのバイナリを作るのが望ましい。

オープンソースじゃないのなら、作者に嘆願するか諦めるか個人の範囲で楽しみましょう。


=mkbundle実行時のメッセージについて=
temp.c: In function 'install_dll_config_files':
temp.c:81:2: warning: pointer targets in passing argument 2 of 'mono_register_co
nfig_for_assembly' differ in signedness [-Wpointer-sign]
In file included from temp.c:3:0:
C:/Mono/include/mono-2.0/mono/metadata/assembly.h:101:15: note: expected 'const
char *' but argument is of type 'const unsigned char *'

mkbundle実行時このメッセージが出力されていても、
致命的では無いようで大丈夫な時は大丈夫。
出ない時もある、よく解からん(´・ω・`)

内容は署名が違うとか言ってるっぽい。書き換えてやれば黙るのかは未確認。



◆mkbundleを自作する
・mkbundleのソースコード
https://github.com/mono/mono/tree/master/mcs/tools/mkbundle

自作したmkbundleを通して出来上がったexeを実行して
this application has requested the runtime to terminate it in an usual way
Please contact the application's support team for more information.
とかってエラーが出たら
MkBundleが実行時、Monoの環境ではなくMS.Net環境で実行されてる。


このエラーはMS謹製のmscorlib.dllを参照したためmono-2.0.dllの実行時に落ちてると思われる。
mkbundle時のログを見れば、MS製のmscorlib.dllを参照しているはず。

Mono用のコマンドプロンプトから"Mono"キーワードをアセンブリ名の前につけて
"Mono Mkbundle.exe[引数略]"とかってして実行してくりゃれ。


未確認な手法ですが、mscorlib.dll等の関連するファイルの署名をsn.exeで上書きすると
mscorlib.dllがMS版のままmkbundleが出来るかもしれない。

しかし、これは許諾以外の使用方法で、権利的に非常に怪しいと思うので、
個人の趣味の範囲でどうぞ。


=出来なかったこと=
mkbundleを単体で動作できるようにしたかったが、どうにも上手くいかなかった。
何か上手い事GUI化出来た方がいたらご一報ください。



◆おまけ
この手法でネイティブ化出来るのはMonoで実装されている機能だけなので、
全ての.Netアセンブリがネイティブ化出来るわけではない。
それを調べるためにMomaというフリーウェアがあるが、コレも割とめんどくさい。

そこで、下記の手法をつかってVS上からあぶり出すことが可能。
バージョンが違うので、dllは自力で入れ替える必要があるが、割と便利だったのでご紹介。
http://jpobst.blogspot.jp/2009/06/mono-in-visual-studio-2010.html


この方法で恐らくIronPythonから出力した.Netアセンブリもネイティブに動かせるんじゃないかと思う、という蛇足。蛇だけに。



◆最後に
この手法は、足がかりに過ぎず、ただ出来ているという状態を超えていません。
よりよい手法がありましたら、一つコメントをいただけると助かります。


この手法が、どなたかの助けとなれば幸いです。
このエントリーをはてなブックマークに追加
LINEで送る

FXAAをXNA4.0で使う

シェーダーコードをボチボチ最適化して、日本語コメントをつけたので公開。
HLSLのSM2.0に対応しているので、他にも使い道があるように思う。

FXAA.fx


使い方は


後はスプライトバッチで全画面描画してくりゃれ。
このエントリーをはてなブックマークに追加
LINEで送る

.NetのRandomクラスから出力される値のムラについて

さんざんゲームを作り、システムを作ってきたはずなのに、
こんな基本的な落とし穴にはまってしまったのでメモ。


Randomクラスなのに使い方次第では完全なRandomにならない

Seedを揃えればそうなるのは仕様だけれど、
意図せずにこんな事があるとは、恐ろしい・・・


まず、Randomをインスタンスする際コンストラクタ引数なしの場合
SeedがEnvironment.TickCountを使用する設定になっている。

よって、連続して複数のインスタンスをほぼ同時に行うと、 同じ結果しか吐き出さなくなる。
というのはここらへんを見ると解ると思う


しかしながら、上記の対応方法でも問題がある。
Seedの値がいくらか違っても、どういうわけか結果に顕著なムラがある。

元々ムラがあるのは内部的に採用しているアルゴリズム上、仕方ないのだが、
それ以上に結果のムラを強く感じる。

検証ソース


結果


このレベルのムラはゲームでは致命的にはならないが、
GAなどでは結果に大きく影響するため、意識的に避けたい。

そういうわけで、複数のインスタンスを作成するより、
ひとつのインスタンスを使いまわす方が結果が優秀であるため、
スタティックでグローバルなクラスを作って、 そこから取得するのが良いのではないかと思う。


以下適当ソース


取得方法


結果サンプル


なんか、ジェネリックとかで、他にもっとうまい方法で出来るような気がするんだけど、
とりあえずこんな感じで。

求ム、最適解。


2012/11/22 追記
RandomをRondomと何度も何度も連呼しているという、
ソーシャルなウィンドーが全開の、まっこと恥ずかしい誤記を指摘していただいた、
通りすがりのご親切な方、誠に誠にありがとうございました。
このエントリーをはてなブックマークに追加
LINEで送る

AndroidでUnityのInput.gyroを使う方法

最近はルーチンに近いプログラムばっかりで、
ここに公開する情報が少なくなってしまって、なんとも寂しい限り。

そんな中、久しぶりに時間ができたので、
Unityの新しい機能(と言っても、もう数か月前のものですが)を試していて、
AndroidでInput.gyroを使うのにハマったのでメモ。


海外の情報を覗いてみると
AndroidでInput.gyro使えねーよ → Input.accelerationが使えるよ → ありがとう!
マテ・・・それは角速度ではない、加速度だ。


当初、SystemInfo.supportsGyroscopeはTrueを返すのに、
Input.gyro.enabledが端末の設定をどう変えてもTrueにならず困っていたら、
Trueはプログラムから自力で突っ込むという謎仕様だった。


ちなみに、Input.gyro.enabledのデフォルトは、何故か『False』。
そして、『False』のままでも、Input.gyro.attitudeを取得すると
[0.0, 0.0, 0.0, 1.0]を常に返すという、不届き仕様。

Input.gyro.enabledをTrueにすることで、初めてちゃんとした値を取得できるようになる。


以下、動作確認用のウルトラ適当ソース。
このエントリーをはてなブックマークに追加
LINEで送る

Enumerable.Repeatでハマった

Enumerable.Repeatの挙動が想像していたのと違うのでメモ


こんな感じのクラスがあったとする
    public class test

{
public int index;

public test(int n)
{
index = n;
}
}
で、それをEnumerable.Repeatを使って、デフォルトコンストラクタを呼び出す。
    test[] array = Enumerable.Repeat(new test(5), 10).ToArray();
すると、結果はarrayのindexはすべて5となる。
ここまでは良い。

そして、それに値をこんな感じでセットする
    for (int i = 0; i < array.Length; i++)

{
array[i].index = i;
}
すると、結果はarrayのindexは、すべて 9 になってしまう。


何故こんな事が起こるかというと、
Enumerable.Repeatは、指定された回数初期化処理を行うのではなくて、
指定された個数のコピーを作るに過ぎないと言うことっぽい。

これ、別のバグとワンセットになって潜んでいた性で、かなり苦労させられた。
Repeatの名に騙された・・・
このエントリーをはてなブックマークに追加
LINEで送る

InvalidOperationExceptionが出るときの引数を犠牲にしない対処法

InvalidOperationExceptionは他のスレッドから、 コントロールの操作を行おうとすると発生する。 「有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'textBox1' がアクセスされました。」等と怒られるはず。 細かいお話は他のサイト様に任せるとして、とりあえずこの例外を切り抜ける方法。 何が起こっているか知りたい人は InvokeRequiredやMethodInvokerあたりを調べると幸せになれると思う。
このエントリーをはてなブックマークに追加
LINEで送る

C#でXMLを扱う時のメモ

XMLを扱っている上で困った、アレコレをまとめてみた。


・クラスをシリアライズしたXMLファイルを読み込む時、
XmlDocumentのLoadでOutOfMemoryExceptionが発生する対処方法


以下のように記述すると、XMLがある一定のサイズを超えると、
doc.LoadでOutOfMemoryExceptionが発生するようになる。


とりあえず、エラーを止めるには記述を以下のように変更すれば良い。


しかし、これだけでは根本的な解決にはならない。
一般的な対応方法は、SQLiteで、おとなしくDBを使うのが結果的に楽で早い。

ところで、肥大化したXMLファイルにjpg等の画像を埋め込んでいないだろうか?
この場合は対処方法がある。


・XML内に画像を埋め込んだ時にサイズが巨大になる対処方法
問題は、jpgやpngで取り込んだはずのデータでも、
すべからく32bitBMP形式で保存されるため、サイズが巨大化する。

これは以下のように、バイナリ化する際にImageクラスをそのまま、バイナリ化するのが原因。

これを解消するには、保存する際にjpgのバイナリにしてやることで回避可能。
もちろん画質はjpgになるが、この対応で読み込み時間が劇的に改善される。

さらにもう一歩踏み込むと、これはメモリ上にはビットマップで持ったままになる為、
プログラムの動作改善にはあまり効果がない。

そこで、使う寸前までJPGのバイナリでメモリ上に保持しておき、使う時に
Image = new Bitmap(new MemoryStream(PictureByteArray))
とした方がメモリ効率がぐっと良くなる。

また、読み込み時のメモリ確保、Bitmapの構築コストが無くなるので、
読み込み時間が更に短くなるはず。


・大きなファイルは直接上書きしない
あと、基礎的な所で、これだけ巨大なXMLを保存するときは直接上書きしてはならない。
以下の実装で書き出し中に万一メモリ不足でプログラムがハングアップすると、
過去データがすべて消える憂き目に合う。



気持ち面倒ではあるが、ワンクッション置くと、万一のとき、被害の度合いがぐっと減る。


以上、XMLアレコレでした。
基本的に、XMLでこのようなメモリをバカ食いする実装は、
本来は望ましくないのではないかと思う。

これらの手法は、ある程度データが増えた場合の一時的な対応なので、
なんらかのDBに移行するために、時間を稼ぐ延命措置ぐらいに思って欲しい。


もしくはXMLをランダムアクセスする、豪快なクラスを作るのも面白いかもしれない。
先頭アドレス、サイズ、キーを保存したファイルを用意すれば、不可能ではないのではないかと思う。
このエントリーをはてなブックマークに追加
LINEで送る

ネットからダウンロードしたアセンブリを読み込む

どうにも思うようにmkbundleが動作してくれないので、いよいよとパッチ作業を始めた。その中で以下のエラーが出て先に進めなくなったのでメモ。

ネットワーク上の場所からアセンブリを読み込もうとしました。これにより、以前のバージョンの .NET Framework で、アセンブリがサンドボックス化された可能性があります。このリリースの .NET Framework では、CAS ポリシーが既定で有効になっていないため、この読み込みは危険な場合があります。この読み込みがアセンブリのサンドボックス化を目的としない場合は、loadFromRemoteSources スイッチを有効にしてください。詳細については、http://go.microsoft.com/fwlink/?LinkId=155569 を参照してください。

要約すると、
『読み込んじゃいけないっぽいアセンブリを読みこもうとしてますぜ、旦那。
どうしてもって言うなら、フラグ変えると幸せになれるかもな。
続きはWebで。』


じゃぁ、続きをと思って見てみると、以下のメッセージが目に入った。
「Visual Studio プロジェクトのエラー一覧に表示されたエラー メッセージ、またはビルド エラーによってこのトピックにたどり着いた場合は、「方法: Visual Studio で Web からダウンロードしたアセンブリを使用する」を参照してください。

要約すると
『お前も、かの場所から来たのか。
ならば、お前の進むべき道は・・・
続きはWebで。』


というわけで続きを開いてみると
方法: Visual Studio で Web からダウンロードしたアセンブリを使用する

あぁ、なるほど。
このエントリーをはてなブックマークに追加
LINEで送る

Unity小ネタ小技集

Unityを始める上でハマったこと、悩んだことをメモ
初心者の書いた内容なので、間違ってる所があったら指摘お願いします。

○VisualStudioで開発する
メニューからEdit→Preferences→GeneralタブのExternal Script Editorから選択

○スクリプトを実行するときの注意点
VSで編集した奴は保存しないと反映されない。

○ステップ実行
VSでは現在のところできない。MonoDeveropならできる

○グローバル変数が表示されない
オブジェクトにグローバル変数(プロパティ)が表示されていないのはPublicになっていないから

○UIをプレビューする
プレビューはクラスの先頭に[ExecuteInEditMode()]をつける

○UIでテクスチャが表示されない
カメラオブジェクトにUIのスクリプトを仕込んでテクスチャを表示しようとすると表示されない。
メニューのGameObject→CreateEmptyで出来上がったオブジェクトに仕込む

○ボタンが文字化けする
VisualStudioのメニューからファイル(F)→名前をつけて〜.csを保存(A)→
上書き保存(S) 横の ▼ を押下→エンコード付きで保存→Unicode - コードページ 1200を選択

○Texture2Dのシリアライズ
標準のTexture2D.EncodeToPNG()でbyte[]を取得可能
Texture2D.LoadImage(byte[])でTexture2Dを取得できる

jpegエンコーダーは海外サイトで見つかる。


○EditorUtilityはビルド後使えない
exメッセージボックス、ファイルダイアログ
SaveFilePanelやDisplayPopupMenuは使えないので自力実装する必要がある


【エラーメッセージ】
○the referenced script on this behaviour is missing!
身に覚えのないスクリプトがオブジェクトに無いかチェック
余分なスクリプトや使わなくなったスクリプトがのこってる場合がある

○unity Unexpected symbol `'
コメントの前とかに全角空白が残ってるとエラー

○NullReferenceException UnityEngine.Camera.ScreenToWorldPoint
カメラのtagにメインカメラの指定が必要

【Tips】
○String.EmptyボタンはiPhoneで重い
1*1の透明テクスチャボタンを使う
このエントリーをはてなブックマークに追加
LINEで送る

mkbundleで発行されるgccのオプション

普通にcygwinからmkbundleをやるのもつまらないので
MinGWとMSYSをつかいcmd.exeだけで処理を完結させようかと思う。


そのため、gccのコマンドを自力発行するべく
mkbundleで発行されるオプションと、
使えそうなオプションを調べてみた。

●書式
gcc「リンカへ渡すオプション」
-o「実行ファイル名」
「コンパイルオプション」
「ソースファイル名」
「オブジェクトファイル名」

●mkbundleで発行されるgccコマンド
○gcc

○-mno-cygwin
cygwin1.dllを必要としないバイナリを作る

○-g
デバッグ情報を生成する

○-o NAME
作成するバイナリの名称を指定

○-Wall
警告を表示する

○temp.c
ソースコード

○`pkg-config --cflags --libs mono-2|dos2unix`
・オプション文字列の自動生成 リンク -lフォルダ名を列挙
CFLAGS=`pkg-config --cflags mono-2`
LDFLAGS=`pkg-config --libs mono-2`

中身はオプションの情報をまとめたもの。

pkg-configコマンドを利用して展開すると以下の様な感じ
(今回は直接MinGWを利用するので-mno-cygwinは全て不要)

dos2unixは改行コードを[CR+LF] -> [LF]とする
(これも同様に不要)

○temp.o
オブジェクトファイル名
(DLLとかもここに書く)


●使用されていないけど、使えそうなオプション
-shared DLL作成用オプション(リンカオプション)
-s オプションでファイルサイズを減少させられる らしい(リンカオプション)
-O1 オー 最適化オプション(リンカオプション)
-O2 高度最適化
-O3 超高度最適化
-O0 最適化を行わない
(最適化のデフォルトは不明)

最適化の詳細はこちらのサイトが詳しい
http://www.cqpub.co.jp/interface/column/freesoft/2002/200208/08-4.htm
このエントリーをはてなブックマークに追加
LINEで送る

Win32用のmkbundleのオプションを、とりあえず訳してみた

Monoを本格的に利用するためにWin32用のmkbundleのオプションを、とりあえず訳してみた。
このエントリーをはてなブックマークに追加
LINEで送る

SlimDXの問題点とSharpDX

ある程度SlimDXでの開発を終え、テストもボチボチ進んだ頃、
「さぁ、仲間内に配布」という所で有る問題が持ち上がってきた。

それは、「必要とするライブラリが多い」という事実。

もともとXNAからSlimDXへ移行したのは
実行するユーザーの負担の少なさを期待してのものだったのだが、
これが外れたのだ。

.Netはそもそも標準インストールではないので、
インストールされていないPCにはインストールが必要となる。
そしてSlimDXはC++ Runtimeが必要なのでこれも必要となる。

結局、これだとユーザーに付随するライブラリを2つ以上要求することになる。
ダメだったときに「.Net入れてね」だけで済まないのだ。

.Netだけであれば「わりと入っているだろう」という楽観の下
.Net 2.0環境で開発を続けていた。
ところが、そうは行かなかった訳だ。


困っていたところに、面白いものを見つけた。
SharpDX
http://code.google.com/p/sharpdx/

これの良いところは
・もちろんC++ Runtimeが不要
・Mono上で動作する(.NET Frameworkも不要)
・SlimDXより高速らしい

悪いところは
・日本語の情報がない


言語の壁があるが、
ある程度対応するAPIが有るであろうことを期待して、
SlimDXから移行をしてみようかと思う。
このエントリーをはてなブックマークに追加
LINEで送る

使い捨てメアドを本当に使い捨てる

取得に情報入力が不要で、破棄も自動的。
本当にページを表示してすぐに使えるメアドサービス。

その名も「10分メアド」
http://10minutemail.com/10MinuteMail/

前は英語のみだったんだけど、いつの間にか日本語に対応してた。


使い捨てメアドを登録すると、そのサイトからメールが来たり、
結局ゴミを片付けるなどのメンテが必要だったりして、
「使い捨て」できていないメアドが増えてきてしまってたのだが、
これで、そういう煩わしさからおさらばできる。
このエントリーをはてなブックマークに追加
LINEで送る

Unityテスト

Unityをブログに貼れないかなぁと模索
続きを読むで表示されるはず。

一回で髪の毛の揺れが止まるのは仕様です。
読み込み終わってからワンテンポ遅れて表示される、はず。
このエントリーをはてなブックマークに追加
LINEで送る

続きを読む »

SlimDXでXAudio2をつかってサイン波を再生する

XAudio2のいろんなサンプルを継ぎ接ぎしてSlimDXに対応させた。


一番困ったのは、転送してるのはByteのくせに、
その中身はShortにしておく必要があるとか、
よく分からない事になってたのに気がつかなくて苦労した。

[2011/11/27追記]
format.BitsPerSample = 16; なんだから当然でした。
24とか32Fによって対応方法を変えてくりゃれ。

32Fはfloatに一旦突っ込んで中身が1.0〜-1.0って表記になる
そいつを、int32に放り込むなら32bitの最大値で掛けて、整数型に直してやればいい。

この方法だと、厳密にはプラス側と、マイナス側で最大1の誤差が出るが、
どう頑張っても聞き分けられないので、無視していいと思う。
[追記終わり]


byte[] byteArray = new byte[waveData.Length * 2]; //バッファ
Buffer.BlockCopy(waveData , 0, byteArray, 0, byteArray.Length);

↑このへん。

それ以外はWaveを扱ったことがある人なら、それほど苦労することはないと思う。
若干クセがあるものの、全体的に簡単な使い心地。
というか、他の音関係のライブラリが難しすぎるんだと思う・・・

そんなわけで、以下サンプル。


XAudio2 device = new XAudio2();
MasteringVoice masteringVoice = new MasteringVoice(device);

WaveFormat format = new WaveFormat();
format.Channels = 1;
format.SamplesPerSecond = 44100;
format.BitsPerSample = 16;
format.BlockAlignment = (short)(format.BitsPerSample / 8 * format.Channels);
format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlignment;
format.FormatTag = WaveFormatTag.Pcm;

// Create the sample data into memory
short[] waveData = new short[format.AverageBytesPerSecond];

//「ラ」を表すsin波(440Hz、1秒)
for (int i = 0; i < waveData.Length; i++)
{
waveData[i] = (short)(32767.0 * Math.Sin(2.0 * Math.PI * 440.0 * i / (double)format.SamplesPerSecond));
}

byte[] byteArray = new byte[waveData.Length * 2]; //バッファ
Buffer.BlockCopy(waveData , 0, byteArray, 0, byteArray.Length);

MemoryStream ms = new MemoryStream(byteArray);
AudioBuffer buffer = new AudioBuffer();
buffer.AudioData = ms;
buffer.AudioBytes = (int)ms.Length;
buffer.LoopCount = XAudio2.LoopInfinite; // 永久にループ
buffer.LoopBegin = 0; // ループ開始位置
buffer.LoopLength = 0; // 再生する長さ。0だと全部。
buffer.Flags = BufferFlags.EndOfStream;

SourceVoice sourceVoice = new SourceVoice(device, format);
sourceVoice.SubmitSourceBuffer(buffer);
sourceVoice.Start(); //再生

MessageBox.Show("終了");

// cleanup the voice
buffer.Dispose();
sourceVoice.Dispose();
ms.Close();
ms.Dispose();

masteringVoice.Dispose();
device.Dispose();
このエントリーをはてなブックマークに追加
LINEで送る

DirectShowLib-2005をWin7で使えるようにする

DirectShowLib-2005をWindows7の64bitで使おうとしたところ
『接続に必要な中間フィルターの組み合わせが見つかりませんでした。』
とかってエラーがでて動作しない。


Windows7ではDirectShowフィルターは
強制的にMicrosoft製の物が優先になるとか何とか(うろ覚え)

まぁ、そのあたりの絡みなのかなぁと思いつつ、
どうせ使わないのでDirectShowフィルターを無効にしてやることで、
とりあえずこの問題をクリアした。


修正はたった1行で
ソース『Capture.cs』内の SetupGraph メソッド中にある、
以下の一行をコメントアウトすればよい。

m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);
このエントリーをはてなブックマークに追加
LINEで送る

シェーダー高速化の肝

今まではXNAのサンプルそのままに
ガウシアンブラーで右方向と下方向をサンプリングしていたのだが、
これを右下、左上に変更するだけで、なぜか高速化されたので覚書き。

TexCoordのサンプラオフセット値の指定を
texcoord + float2(x,0);
texcoord + float2(0,y);
から
texcoord + float2(x,y);
texcoord - float2(x,y);
と変えるだけで780->920fpsという、となかなか大き変化があった。

時間に直せば0.0002秒の差だが、
低速なマシンではボチボチ効果がある差なのではないかと思う。

一体何がどうしてこの速度の差に現れたのか、すごく気になる。
そこで、あれこれ試してみたところ、
少しコードの書き方を変えるだけで30fpsくらいは、ぴょこぴょこと簡単に変化が出る。

シェーダにおいてはコンパイラさんが気に入るコードを書くことが、
高速化の肝なのだなぁと身を持って感じた。
このエントリーをはてなブックマークに追加
LINEで送る

SlimDXでeffectが使える2D描画の方法

偉そうに書いているが、TEXCOORD周りが厳密には間違っている気がする。
見たところの動作は良好。

この実装では必ずClientサイズとTextureサイズが等しいこと。
RenderTargetから値を持ってきた時を想定しているので、この形に。

Effectまわりは自分で追加してくりゃれ。


[StructLayout(LayoutKind.Sequential)]
struct Vertex
{
public const VertexFormat Format = VertexFormat.Position | VertexFormat.Texture1;

public Vector3 Position;
public Vector2 TextureCoordinate;
}

public partial class Form1 : Form
{
// Direct3D9 Device
static Device _device;
// テクスチャ
static Texture _texture;
// テクスチャ描画用の頂点バッファ
static VertexBuffer _vertices;

public Form1()
{
InitializeComponent();

var pp = new PresentParameters();
pp.BackBufferWidth = this.ClientSize.Width;
pp.BackBufferHeight = this.ClientSize.Height;

_device = new Device(new Direct3D(), 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, pp);

// カラー成分の設定
_device.SetTextureStageState(0, TextureStage.ColorOperation, TextureOperation.SelectArg1);
_device.SetTextureStageState(0, TextureStage.ColorArg1, TextureArgument.Texture);
// アルファ成分の設定
_device.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.SelectArg1);
_device.SetTextureStageState(0, TextureStage.AlphaArg1, TextureArgument.Texture);
// ブレンディングモードの設定
_device.SetRenderState(RenderState.AlphaBlendEnable, true);
_device.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha);
_device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);


// テクスチャを sample.png から読み込む
_texture = Texture.FromFile(_device, "test.bmp", 0, 0, 1, Usage.None, Format.A8R8G8B8, Pool.Managed, Filter.None, Filter.None, 0);

var description = _texture.GetSurfaceLevel(0).Description;

// 頂点のサイズ (バイト)
int vertexSize = Marshal.SizeOf(typeof(Vertex));
// 頂点バッファを作成
_vertices = new VertexBuffer(_device, 4 * vertexSize, Usage.WriteOnly, Vertex.Format, Pool.Managed);
// 頂点バッファをロック
var dataStream = _vertices.Lock(0, 4 * vertexSize, LockFlags.None);

// テクスチャ座標の指定
float x1 = 0.5f / description.Width;
float y1 = 0.5f / description.Height;
float x2 = (pp.BackBufferWidth + 0.5f) / description.Width;
float y2 = (pp.BackBufferHeight + 0.5f) / description.Height;

// 頂点バッファにデータを書き込む
dataStream.WriteRange(new[] {
new Vertex { Position = new Vector3(-1.0f, 1.0f, 0.0f), TextureCoordinate = new Vector2(x1, y1) },
new Vertex { Position = new Vector3(1.0f, 1.0f, 0.0f), TextureCoordinate = new Vector2(x2, y1) },
new Vertex { Position = new Vector3(-1.0f, -1.0f, 0.0f), TextureCoordinate = new Vector2(x1, y2) },
new Vertex { Position = new Vector3(1.0f, -1.0f, 0.0f), TextureCoordinate = new Vector2(x2, y2) },
});

// 頂点バッファをアンロック
_vertices.Unlock();
}

public void Run()
{
SlimDX.Windows.MessagePump.Run(this, Draw);
}

void Draw()
{
// 画面をクリアする
_device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0);


_device.BeginScene();

// 描画する頂点バッファを指定する
_device.SetStreamSource(0, _vertices, 0, Marshal.SizeOf(typeof(Vertex)));

// 頂点バッファのフォーマットを指定する
_device.VertexFormat = Vertex.Format;

// テクスチャを指定
_device.SetTexture(0, _texture);

// 描画する
_device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);

_device.EndScene();

// 表画面に描画内容を転送
_device.Present();
}

このエントリーをはてなブックマークに追加
LINEで送る

超ニッチなエクセルグラフの作り方

一体どこに需要があるかさっぱり解りませんが、
「2軸上の折れ線と積み上げ棒グラフ」の作成と、
その調整方法をメモ


グラフ作成時に[ユーザー設定]→[2軸上の折れ線と縦棒]から
[2軸上の折れ線と積み上げ縦棒]にする方法は、
適当な棒グラフを右クリック→「グラフの種類」→「縦棒」→「積み上げ縦棒」とすればOK

ここから、折れ線グラフになってしまった値は、
対象の折れ線グラフを右クリック→データ系列の書式設定→軸のタブ→第2軸から主軸
さらに、棒グラフを右クリック→「グラフの種類」→「縦棒」→「積み上げ縦棒」とすればOK

そこからさらに順番を変更したい場合は
適当な棒グラフを右クリック→データ系列の書式設定→系列の順序タブ→上へ移動、下へ移動ボタン


軸を調整せずに見た目だけ変更していると、この順番が変更できず、
まるで項目が表示されていないように見えるのでハマった。
このエントリーをはてなブックマークに追加
LINEで送る

SlimDX.D3D9を使いGPUで描画した結果をCPUで取得する

相変わらず海外を含めてサンプルが見つからない。

SlimDXでGPGPUをDX9のまま実装するため
描画済みのテクスチャを取得する方法を置いとく

描画メソッド内に以下の内容を実行すると、取得ができる。

テスト用のメソッドなので、ビットマップの保存や、
巨大な配列の宣言とかは適宜修正してくりゃれ。


//レンダーターゲットを用意する
renderTexture = new Texture(device, this.ClientSize.Width, this.ClientSize.Height, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
renderSurface = renderTexture.GetSurfaceLevel(0);

//レンダーターゲットを保存する
oldRenderSurface = device.GetRenderTarget(0);

//レンダーターゲットを変更する
device.SetRenderTarget(0, renderSurface);

//画面を初期化
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
device.BeginScene();

//データを流しこんで描画
device.SetStreamSource(0, vertices, 0, Marshal.SizeOf(typeof(Vertex)));
device.VertexDeclaration = vertexDecl;
device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

//レンダーターゲットを元に戻す
device.SetRenderTarget(0, oldRenderSurface);
oldRenderSurface.Dispose();

//ストリームを用意
DataStream stream = Texture.ToStream(renderTexture, ImageFileFormat.Bmp); //ファイルストリームと等価

//ビットマップとして流しこむ
Bitmap bmp = (Bitmap)Bitmap.FromStream(stream, false, false);

//内容を保存して確認
bmp.Save("test.bmp", System.Drawing.Imaging.ImageFormat.Bmp);

//直接バイト型として参照も可能
byte[] bs = new byte[stream.Length / sizeof(byte)];
stream.Read(bs, 0, bs.Length);

device.EndScene();
device.Present();



はっきり言って暗中模索のなか、どうにか実行できているレベルなので、
このままでは問題が起こる可能性が多分にある。

メモリリークの可能性や、その他何か気づいた点があったら、
遠慮なくコメントからツッコミをお願いします。


蛇足:
国内のサンプルは何故かテクスチャを
一生懸命BitmapクラスやらImageクラスからメモリ通して作ってるけど、
なんで
Texture tex = Texture.FromFile(device, filePath);
を使わないんじゃろうか・・・

低速であっても、どうせ初期化の一回きりの処理だし、
気にならないと思うんだけど、何か理由があるんだろうか・・・
このエントリーをはてなブックマークに追加
LINEで送る

Windows7でWindowsXPのペイントを使う

かなり高機能なったWindows7のmspaint

しかし、使い慣れない部分も多く、あの機能がなくなったなぁ・・・
と思うことも多い。
なんか、この行はどこかで見たような気がするが気にしない。

そこで、使わなくなった正規XPのCDを破棄したり、中古でPCショップに渡さず、
XPをインストールしていた時にバックアップをしたmspaint.exeさんを
Windows7マシンにコピーし実行しましょう。

すると、ちゃんと懐かしのあの画面が出てきます。
機能的な制限もなく、exe一つで簡単に実行できます。


HDDがクラッシュして使わなくなった古いPCからリカバリCDをもらったりすれば、
権利的にもグレーにはなると思う。

くれぐれも友人のパソコンや学校、職場のパソコンからコピーだけしないように。
ホログラムに輝く正規CDを胸に行うこと。


ちなみにXPのバージョンである5.1は、ほぼそのまま使えるのですが、
2000のバージョンである5.0はjpeg保存ができなくなります、トホホ。
このエントリーをはてなブックマークに追加
LINEで送る

密かなるSlimDX

最近SlimDXを始めた。

んが、しかし。
XNAとぜんぜん使い勝手が違う。
なんていうか、ラップが薄く、”楽”じゃないなぁという感じ。

しかも!なかなかと変な癖があって
Vector3.Transformの戻り値がVector4だったり、
Colorの持ち方がint型だったり、そこかしこに罠が潜んでいる。

そのあまりの違いに、まともにモデルを表示することもままならず、
途方にくれていた。


その原因はとにかくサンプルがない。
情報の殆どは英語と、なかなか敷居が高い。

たかだかインデックスバッファのサンプルを探しても、
どうやら存在しないのだから泣けてくる。

仕方ないのでDirectXのサンプルやらXNAの記憶とかを便りになんとか、
シンプルなIndexBuffer描画サンプルを作成したので、ここに置いておく。



実行結果


using SlimDX;
using SlimDX.Direct3D9;
using SlimDX.Windows;

using System.Runtime.InteropServices;

namespace IndexbufferTest
{
public partial class Form1 : Form
{
Device device;

public struct TestVertex
{
public Vector3 Position;
public Vector3 Normal;
public int Color;
}

VertexElement[] vertexElementsArray = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0),
new VertexElement(0, 24, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0)
};

Vector3[] vectors = new Vector3[] { new Vector3(-1, 0, 0),
new Vector3(0, 1, 0),
new Vector3(1, 0, 0),
new Vector3(0, -1, 0)
};

public Form1()
{
InitializeComponent();

var pp = new PresentParameters();
pp.BackBufferWidth = this.ClientSize.Width;
pp.BackBufferHeight = this.ClientSize.Height;
pp.DeviceWindowHandle = this.Handle;

this.device = new Device(new Direct3D(), 0, DeviceType.Hardware, this.Handle, CreateFlags.HardwareVertexProcessing, pp);
}

public void Run()
{
SlimDX.Windows.MessagePump.Run(this, Draw);
}

protected virtual void Draw()
{
int vertexSize = Marshal.SizeOf(typeof(TestVertex));

VertexBuffer vertexBuffer = new VertexBuffer(device, vectors.Length * vertexSize, Usage.None, VertexFormat.None, Pool.Managed);

var vertexData = new TestVertex[vectors.Length];
for (int i = 0; i < vertexData.Length; i++)
{
vertexData[i].Position = vectors[i];
vertexData[i].Normal = new Vector3(0, 0, -1);
vertexData[i].Color = Color.Gold.ToArgb();
}


IndexBuffer indexBuffer = new IndexBuffer(device, vectors.Length * sizeof(uint) * 3 - 2, Usage.None, Pool.Managed, false);
var indices = new uint[]{0, 1, 2,
0, 2, 3};

device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.CornflowerBlue, 1.0f, 0);
device.SetRenderState(RenderState.Lighting, false);
device.BeginScene();

device.VertexDeclaration = new VertexDeclaration(device, vertexElementsArray);

DataStream vertexBufferStream = vertexBuffer.Lock(0, vectors.Length * vertexSize, LockFlags.None);
vertexBufferStream.WriteRange(vertexData);
vertexBuffer.Unlock();
device.SetStreamSource(0, vertexBuffer, 0, vertexSize);

DataStream indexBufferStream = indexBuffer.Lock(0, indices.Length * sizeof(uint), LockFlags.None);
indexBufferStream.WriteRange(indices);
indexBuffer.Unlock();
device.Indices = indexBuffer;

device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vectors.Length, 0, indices.Length / 3);

device.EndScene();
device.Present();
}
}
}
このエントリーをはてなブックマークに追加
LINEで送る

これは便利だ・・・

超基本なんですが、今までずーっとこれで苦労していた。

タブ遷移

こいつを自動的にささっと指定する方法はないかと、
何度も探しては挫折していたのですが、
ようやく見つかった。


メニューバー[表示(V)]→タブオーダー(V)としてから、
遷移させたい順にオブジェクトをクリック
そこからメニューバー[表示(V)]→タブオーダー(V)で確定


今まではそれほど画面数がなかったので、
我慢して自力でやってましたが、いつからこの機能あったんだろう・・・

確か、前の会社でメジャーバージョンアップ時にタブオーダーの変更で、
2人日くらいスケジュールがとったような記憶が・・・・・・(汗
このエントリーをはてなブックマークに追加
LINEで送る

 | HOME |  NEXT »

PAGE TOP ▲

Appendix

■春条

■春条

生息地は愛知
車と甘い物が好きな31歳
特技は無限昼寝

MONOからSharpDXを使う
変態的な手法で、
.NET Frameworkを使わずに
ゲーム作りやってます。

Search

Calender

« | 2017-07 | »
S M T W T F S
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -

Twitter

Recent Entries

DTIブログポータルへ
このブログを通報
Report Abuse

利用規約