MacOS XでWX320K,WX341K(Willcom)非公式JAVAアプリの作成

(2009/03/14-)


今更であるが、NTT DocomoがPHSサービスを停止したときにもらったWillcom WX320Kで動く非公式JAVAアプリをMacOS X上で作ろうと思い立ち悪戦苦闘し たメモです。

開発環境:MacBook Air, Mac OS X 10.5.6, Xcode 3.1, WTK2.5.2

WX320Kで動作する非公式JAVAアプリの開発は下記の手順でおこなう。
netbeenやeclipsやxcodeの統合環境は使わずまたjavaのビルドコマンド antやGUIのktoolbarも使わず、gmakeでもなく男らしくmakeでビルドする。 (下記のHello! Worldサンプルプログラムにはantのbuild.xmlも入れてあります)
(後日追記:と思ったのだが、そもそもMacOS Xに入っているmakeはgmakeでした。 サンプルに放り込んだMakefileでもgmake固有の記述を含んでいます)

JavaのJ2MEなどのクロス開発ではソースをコンパイルするときにシンボルを解決 するためにスタブライブラリ(jar)が必要だ。MIDPなどのスタブライブラリは下記の 開発キットに入っている。

J2MEの開発は J2ME Wireless Toolkitという開発環境が用意されていが Mac用は用意されていない。しかしLinux用があるのでこれをダウンロ ードして、ファイルをchmod a+xして実行して中身を取り出す。

上記に含まれるlibにあるjarファイルにクラスパスを通してコンパイル してクラスファイルが作れるのだが大きな落とし穴がある。JDK 1.5の javacでコンパイルして実機で動かすと"java/lang/NoClassDefFoundError" で動作しない。JDk 1.4のjavacを使うか、-targetで1.3などを指定する 必要です。ビルドしたクラスファイルがどのバージョンでコンパイルされ ているかはfileコマンドで確認できます。
% file Sample.class
Sample.class: compiled Java class data, version 47.0
preverifyコマンドはバイナリのためLinuxのパッケージに入っている バイナリは動きません。 ここを 参考にして調べてみたとろ現在はjava.netの phoneme プロジェクトからソースを拾ってきてビルド出来るようです。
svn checkout https://phoneme.dev.java.net/svn/phoneme/components/preverifier/trunk/src phoneme --username guest
(パスワードは空)
上記のコマンドでソースが拾えるので下記にあるサンプルの中にある preverifyディレクトリのファイルを上のチェックアウトしたディレクトリに コピーしてmodsrc.shファイルを実行してmakeするとコマンドが出来ます。 小さいサンプルであればpreverifyで処理しなくても動作するようだが、 ちょっとでも大きくなると、"java/lang/error"と表示されてきで起動 できません。ライセンス上ビルドしたファイルの配布は不可能なようです。 (ひょっとすると昔話かもしれません)ただソースはMac OS(DARWIN)でも ビルドしているようです。

Javaで書かれたMicroEmulatorという オープンソースのエミュレータがMacOS Xでも使えるようだ。漢字の表示も 問題なく出来ている。下のサンプルのキャプチャーはこのツールでおこなっ ている。注意が必要なのはMath.atan()などはこのエミュレータでは使える が実機では使えない。

preverifyを使わずにProGuard というjarの最適化・難読化ツール(こちらもオープンソース)を使っても同 じ効果があるのかもしれないが未確認。

マニフェストファイルやjadファイルのエントリーに問題があると インストールや実行できない事もあるので注意が必要です。

jadファイルはマニフェストファイルにjarファイル名とファイルサイズ を追加したものです。

ファイルのコピーは Kyopon USB DriverKyopon File Utility で行い、WX320Kのデータフォルダでjadを選択して実行するとインストールが 始まります。

通信するプログラムは「JAVAアプリ」の「接続先設定」を「CLUB AIR-EDGE」 からほかのISPなどに変えないと通信できない。WILLCOMが提供している PRINを設定してもよい。 CLUB AIR-EDGEでOperaでアクセスしてもprinのIPなのになぜ、 こんな区別をするのだろうか?

WX320KにはMascotCapsule という3D描画エンジンが入っている。このSDKとサンプルプログラムをダウンロード してビルドできた。このような機能はエミュレータが提供されている環境でも 実機でしか確認できないようだ。

MascotCapsuleの開発は、3Dモデリングソフトでモデリングをおこなった後に 指定の形式にデータを出力して、それを再度変換したファイルをjarに突っ込 む必要がある。この環境にしか用意されていないので、 MacでMascotCapsuleの完結した開発環境を作る事は出来ない。 せっかくJavaで環境依存せずにバイナリが作れるのでJavaな変換ソフトなどが あると良いのだが。

J2ME環境でも機種によってはXMLの処理ができるJSR172をいうAPIが使えるようだが WX320Kでは使えない。このためkXMLというオープンソースを使ってみた。

HTTPするアプリを作ってみたのだが、InputStreamはJ2SEとJ2MEで使えるが BufferedReaderはJ2MEでは使えない。ただ救いは、kXMLはInputStreamReader が入力になるので両用のコードがかける。

日本語を含むXMLはUTF8の事が多いので以下のようにすると良いようだ。
KXmlParser parser = new KXmlParser();
parser.setInput(new InputStreamReader(input, "UTF8"));
いろいろ自作アプリを試していると、体感的にそんなに早くはないって感じが する。現実的に使えるアプリを作るにはサイズの制限はほぼ無いに等しいが、 体感スピードを速くするチューニングは必須かもしれない。

ネットワーク系のプログラムを試していると、通信を行うのでお金がかかる。 私は最低料金のプランなのであまり無茶は出来ない。下記のkXMLのRSS処理も HTTPのコードは入っているがjarに入れたxmlを処理するようにしてある。

貧乏性なので後日追記(先月の利用状況)
ご利用パケット数金額内訳
4720パケット254円4720パケット×0.0525円
PRINご利用時間金額内訳
0時間33分54.0秒170円33分×5.25円
端数処理は不明。。。

RecordStoreは世の中のサンプルはindexを0から処理する物がほとんどだが なぜかWX320KではgetRecord(0)するとExceptionが発生する?

WX320Kでは位置情報とカメラ機能の拡張は使えない。

Math.atan()の用にMicroEmulatorでは使えるが実機では使えないメソッドは ProGuardでjarを処理するとエラーとして出てくる。

J2ME_POMでMath.atan()が使えないためローカルにコードを突っ込んであるが 薄明の計算のソースを見つけて使おうと思ったところ今度ははasin,powがないと ProGuardでエラーが出た。面倒なのでオープンソースのMathライブラリを探して みたところ DFP(LGPL)Real(GPL) というコードが見つかった。Realでpowの使い方は以下です。
//  r = Math.pow(10, r);
    String restr2 =  Double.toString (r);
    Real reobj = new Real(10);
    Real reobj2 = new Real(restr2);
    reobj.pow(reobj2);
    Double reDoub =  Double.valueOf(reobj.toString());
    r = reDoub.doubleValue();

薄明の計算はオープンソースのコードをそのまま使うと実機で1分以上かかってし まう。これは1分毎に24時間分チェックしていて、24×60回ループしているのが原 因のようだった。日の出・日の入りの時間が計算できていて薄明だけの計算であ れば、それぞれの時間から天文薄明までの時間までの計算をすればよい。これに より10秒近くまで処理時間を短縮できた。おおよそ薄明はそれぞれ2時間なので 2×2÷24で計算通りである。(日の出・日の入りに必要な計算も省きました)

上の薄明の計算に使っているJavaコードは ここの JAVA Scriptを移植したように見える。今時のパソコンであれば1秒程度で計算 できるのだが。

上のオプティマイズは最初すべての処理をRealベースで計算しようとしたところ、 いろいろ面倒で、部分的にRealベースなコードを試したところ逆に遅くなったので 苦肉の策です。

WX320KでフォントはSIZE_LARGE(20),SIZE_MEDIUM(16),SIZE_SMALL(12)が使えるが SIZE_LARGEはあまり奇麗ではない感じだ。

Calendar.getInstance()とタイムゾーンを指定せずにインスタンスを取得すると 月末になると何故かCalendar.MONTHなどが狂いだす。タイムゾーンはVMの実装依 存のようだ。WX320Kには"Asia/Tokyo"などが5つあるようだ。 決め打ちでもまったく問題ないので、意味があまりないサンプルコードは下記に なります。
String tokyoTZ;
String[] tzIDs = TimeZone.getAvailableIDs();
for (int i = 0; i < tzIDs.length; i++) {
  if(tzIDs[i].compareTo("Asia/Tokyo") == 0)
    tokyoTZ = tzIDs[i];
  if(tzIDs[i].compareTo("JST") == 0)
    tokyoTZ = tzIDs[i];
}
TimeZone tz = TimeZone.getTimeZone(tokyoTZ);
Calendar cal = Calendar.getInstance(tz);
WX320KではFileConnectionでアクセスする時のパスは"file:///data/"である。 機種依存しないためにはFileSystemRegistry.listRoots()でルートを取るのが 良さそうだ。

MascotCapsuleでのテクスチャーは256色のbmpファイルを使っている。このため J2MEのオフスクリーンで用意したImageを直接貼る事はできない。またImageは 24bitなので減色処理した上で変換しなければならない。この時に以下のような 選択肢がある。
J2ME環境はあまりパワーがないので、上の二つが現実的ではないだろうか。

JavaでTarフォーマットをサポートするコードはANTの中と ここあるがどちらも J2MEではサポートされていないクラスを使っているのでそのままでは使えない ようだ。

WX320Kのアプリごとの「許可設定」には
とあるが、1度はグレーアウトして選べない。。。

通信が必要なとき以外パケット通信の切断を行いたいのだが方法が分からない。

結局J2SEを対象にしたオープンソースJ2MEに変更するのはあきらめて、超いい加減な TARファイルの取り込みのコードを書いた。20年くらい前にもMacでTarファイルを処理 するコードをいじった事をぼんやり思い出した。。。

MicroEmulator 2.0.3をMac OS Xで使った時のHTTPリクエストのヘッダー
GET /hotnews.rss HTTP/1.1
User-Agent: Java/1.5.0_20
Host: localhost
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
MicroEmulator 2.0.4をMac OS X 10.6で使った時のHTTPリクエストのヘッダー
GET / HTTP/1.1
User-Agent: Java/1.6.0_29
Host: 10.0.1.34
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
MicroEmulatorでhttpsすると200なのにgetLengthが-1になってしまう。WX320Kでは 正常に動作するのだが。。。

上記の許可設定は証明書がある物だけが、パーマネントに許可できるのかもしれな いが、詳細はよく分からない。

下記のMascotCapsuleで回転のために3次元アフィン変換を繰り返すと誤差のためか 図形が歪んだりする。360(4096)回った時は元に戻すのが良いのかもしれない。

3Dの理解のためMascotCapsuleのAffineTransのlookAtの図解を書いてみた。
lookAt

機種変更してWX341Kにしました。これ以降はWX341Kについて書きます。

bouncycastleを使ってOAuthのoauth_signatureを作る方法。動くまでに一日かかり いろいろはまりました。まず仕様書にはPOSTを推奨とありましたが参考にしたコー ドがGETだったので、そうなっています。あと実際にアクセスは最初のoauth_callback だけをURLにつけて、残りとジネレートしたシグネチャーはヘッダーに入っています。 ヘッダーでは値はすべて""で囲まれてセパレターは,になっています。URLencodeは最 近の厳しい仕様でエンコードしないと駄目で大文字でとか除外文字とかひっかかりま した。パラメータについてはキーの名前でソートしないといけません。ちょっとでも 違っているとダイジェストは全く別になりますから面倒です。
	String rtoken = "xyz";
	String key = "abc" + "&";
	long currentSec = System.currentTimeMillis() / 1000L;
	long currentMSec = System.nanoTime();
	String param1 = "GET";
	String param2 = "http://twitter.com/oauth/request_token";
	String param3 = "oauth_callback=oob&" +
		"oauth_consumer_key=" + rtoken + "&" +
		"oauth_nonce=" +  Long.toString(currentMSec) + "&" + 
		"oauth_signature_method=HMAC-SHA1&" +
		"oauth_timestamp=" +  Long.toString(currentSec) + "&" + 
		"oauth_token=&" + 
		"oauth_version=1.0";
	String escapeStr = Util.URLencode(param1) + "&" +
		Util.URLencode(param2) + "&" + Util.URLencode(param3);
	System.out.println(escapeStr);
	byte[] m = escapeStr.getBytes();
	HMac hmac = new HMac(new SHA1Digest());
	byte[] resBuf = new byte[hmac.getMacSize()];
	hmac.init(new KeyParameter(key.getBytes()));
	hmac.update(m, 0, m.length);
	hmac.doFinal(resBuf, 0);
	System.out.println(Base64Coder.encodeString(resBuf));

BAUMのHttpConnectionのヘッダーは以下の通り。FreeBSDのncコマンドでポートを LISTENして確認。
GET / HTTP/1.1
Accept: */*
Host: hoge.jp
User-Agent: JV-Lite2WE/3.3(WILLCOM/WX341K) Profiles/MIDP-2.0 Configuration/CLDC-
1.1
Pragma: no-cache
Cache-Control: no-cache
Connection: Keep-Alive
Accept-Encoding: deflate, gzip

HttpConnectionのsetRequestPropertyでヘッダーをセットした時に256で切れてしまう。 おそらくJV-Lite2の制限事項なのではないだろうか。これだとtwitterのOAuthは 使えない。
サーバがgzipをサポートしている場合はHttpConnectionでの通信はgzipで行われて、 openInputStreamで開くInputStreamは解凍されたデータになるようだ。

上の問題の回避のために、自前でSocketはって、HTTPするコードを書いてみたが、 これでtwitterのAPIをたたいてXMLを拾うととんでもなく遅くてkXMLがIOException を起こす。一度メモリに落としてからkXMLにかければ問題ないようだが、遅すぎて 使い物なりません。setRequestPropertyの制限どうにかしてください。WILLCOMさん

GearのUIではおそらくメモリ節約のためにインスタンス化を繰り返し行わずクラスを 使い回す事を考えて作られているように思われる。これと関係はわかないのだが 時々固まる。。。デバッグの切り口が見当たらない。

Managerのサポートの確認
getSupportedContentTypes: audio/x-pdxmidi
getSupportedContentTypes: audio/wav
getSupportedContentTypes: audio/x-tone-seq
getSupportedContentTypes: audio/x-wav
getSupportedContentTypes: audio/midi
getSupportedContentTypes: application/x-midi
getSupportedContentTypes: audio/sp-midi
getSupportedContentTypes: audio/x-midi
getSupportedContentTypes: audio/x-gpoint726
getSupportedProtocols: https
getSupportedProtocols: device
getSupportedProtocols: file
getSupportedProtocols: http
BAUMでWAVファイルの再生を試していたのだが、なかなかうまくいかなかった。 でよくよくWILLCOMのサイトを見ると以下が見つかった。

wav(G.726 量子化ビット数:2/4bit  サンプリング周波数:8/16/32KHz)

通常WAVファイルはリニアPCMな16bitファイルになっているがそれではだめでWAV ファイル中にG.726なデータを突っ込まないと駄目のようだ。SOXはCODECのサポ ートはないので、ちょっと探してみたが適当がものがみつからなかったので、 soft-switch.orgのspandspという ライブラリに含まれるG.726なコードを使って簡単なコマンドを 作ってみた。(g726encode.tgz spandsp のソースをダウンロードして圧縮ファイルの中身をsrcディレクトリに入れて make -f Makefile.g726するとコマンドが出来る。デバッグライトいろいろは いっているので汚いです)32000Hz/1ChなWAVファイルを食わせるとG.726なWAV を作ります。ちょっと苦戦したのはPCMなファイルを食わせてもまったくエクセ プションなどエラーが出なかったからだ。再生のコードは下記のような感じ。

  public void soundPlay(){
    try {
      Player myPlayer;
      InputStream is = getClass().getResourceAsStream("receive.wav");
      myPlayer = Manager.createPlayer(is, "audio/x-wav");
      if(myPlayer == null) {
        Logger.out.println("Manager.createPlayer error");
      } else {
        myPlayer.addPlayerListener(this);
        myPlayer.realize();
        myPlayer.prefetch();
        myPlayer.setLoopCount(1);
        VolumeControl vc=(VolumeControl)myPlayer.getControl("VolumeControl");
        if(vc != null)
          vc.setLevel(100);
        myPlayer.setMediaTime(0);
        myPlayer.start();
      }
    } catch (IOException ioe) { 
      Logger.out.println("IOException: " + ioe);					
    } catch (MediaException me) { 
      Logger.out.println("MediaException: " + me);					
    }
  }
WX320Kのガイドを見るとNECの μPD9995 というサウンドチップを使っているようなので BAUMもおそらく同じなのであろう。このチップ自体にはG.726のデコーダーとか は入っていないようなので、ホストCPUでデコードしているのかもしれない。

以下でCOM1が存在する事が分かるのだが、このCOM1はローカルポートすなわちUSB接続 されたパソコンとの接続でIrDAのポートではない。JavaアプリからIrDA使えるように してほしい。
  String ports = System.getProperty("microedition.commports"); 
J2MEとは関係ないがFelicaで三者間通信してブラウザを起動するコードを見つけたので ちょっといじって、動くようにしてみた。元々のコードはlibpasoriを使っていたが libpafeに変更してみた。libusbの古いバージョン(0.1.12)とlibpafeをダウンロード してlibusbはconfigureしてMakefileしておいて、libpafeのtestsフォルダーに この(browser_startup.tgz)ファイルを展開して makeすればバイナリーができる。libusbはMakefileでinstall_name_toolしているので システムにインストールする必要はありません。使い方は以下のような感じで、 一度実行した後には引数を空にして実行して三者間通信モードを解除してください。
% browser_startup http://www.google.co.jp/
忘れないうちに書いておくが、以下のようなコードだとLocationがNoClassDefFoundError になり、microemulatorで起動しなくなる。
	try {
		if(onMicroEmulator) {
			startProgress("Get current location near Mobile Point list");
			MobilePoint search = new MobilePoint(this, 35.68381981, 139.77456498);
		} else {
			startProgress("Get current location near Mobile Point list");
			Location loc = Location.deviceActive();
			MobilePoint search = new MobilePoint(this, loc.convertDegree(loc.getLatitude()),
				loc.convertDegree(loc.getLongitude()));
			loc.deviceDeactive();
		}
	} catch (Exception e) {
	}
以下のコードだとOKでした。
	if(onMicroEmulator) {
		try {
			startProgress("Get current location near Mobile Point list");
			MobilePoint search = new MobilePoint(this, 35.68381981, 139.77456498);
		} catch (Exception e) {
		}
	} else {
		try {
			startProgress("Get current location near Mobile Point list");
			Location loc = Location.deviceActive();
			MobilePoint search = new MobilePoint(this, loc.convertDegree(loc.getLatitude()),
				loc.convertDegree(loc.getLongitude()));
			loc.deviceDeactive();
		} catch (Exception e) {
		}
	}
Socketの使い方1
	StreamConnection connection;
		connection = (StreamConnection) Connector.open("socket://" + httpserver);
		PrintStream output = new PrintStream(connection.openOutputStream() );
Socketの使い方2
	SocketConnection sc;
		sc = (SocketConnection)Connector.open("socket://" + httpserver);
		sc.setSocketOption(SocketConnection.SNDBUF, 512);
		sc.setSocketOption(SocketConnection.RCVBUF, 1024*8);
		PrintStream output = new PrintStream(sc.openOutputStream() );
忘れないうち書いておくが、LocationのconvertDegreeでエクセプションを起こして deviceDeactiveしないと次のdeviceActiveでエラーになる。convertDegreeで エクセプションを起こさないように以下のようにチェックして処理にすると良い。
	try {
		Location loc = Location.deviceActive();
		String latStr = loc.getLatitude();
		String lonStr = loc.getLongitude();
		double latVal = 0;
		double lonVal = 0;
		if(latStr.length() != 0 && lonStr.length() != 0) {
			latVal = loc.convertDegree(latStr);
			lonVal = loc.convertDegree(lonStr);
		}
		loc.deviceDeactive();
		if(latVal != 0 && lonVal != 0) {
			// do something
		} else {
			// error
		}
	} catch (Exception e) {
	}
J2MEには正規表現のサポートがない。Stringのsplitはどっかからコードを拾って きてソースに組み込んでいた。ちゃんとした正規表現のオープンソースのライブラリ では Jakarta Regexpdk.brics.automatonがある。 ただし両方ともSerializableを使っているので、これを削除する必要がある。 またJakarta Regexpではjava.lang.Characterを使っていてdk.brics.automaton ではjava.util.Setを使っていて、そのまでは使えない。java.lang.Characterについて はRECharacter.javaという必要な部分だけ実装したコードが見つかったので、これで 置き換えて使えるようになった。

Yet Another J2ME Application 始めました。

上のプロジェクトのWEBホストから直接インストールできるようにしようとした ところ、jarのContent-Typeがapplication/x-java-archiveとなってしまってい たので.htaccessで以下を設定した。
AddType application/java-archive jar
WILLCOMのJAVA機種情報をみるとHONEY BEE 4/BAUM/WX340Kなどは 「CLUB AIR- EDGE経由通信」が「アプリダウン ロード元サーバ」となっている。 yaj2meappのsfのサイトで試してみたが確かにこのサイトからダウンロードした アプリはこのサイトへのアクセスがprinではなくても出来ている。sfのホスティング のphpでproxyの用なコードを作っておけば、prinの1500円は払わないでもすむかもし れない。機種によってアクセス制限が「公式アプリ」や「制限なし」などになって いるが、なぜアクセス制限が機種依存するのか不思議だ。

BAUMでネットからアプリをインストールする場合、ブラウザでjadファイルのリンク からのjarファイルの読み込みにはJAVA接続先設定が利用されるようだ。 この時はCLUB AIR-EDGEに設定してあっても、どこのサーバからでもダウンロードは 出来る。

J2ME_POMに計算時間の表示を入れてベンチマークをとってみたところWX320Kは12秒 くらいで、BAUMは7.5秒くらいであった。Airで動いているmicroemulatorだと0.7秒 位なのだが。。。

J2ME_JSONにもアクセス時間の表示を入れたところ5秒くらいである。重い計算は サーバのPHPに任せた方がよいのかもしれない。

pngの最適化はImageOptimが良いようです。

Hello! Worldサンプルプログラムとpreverifyパッチ
フォルダー名をJ2MESampleから適当な名前に変えてmodifyname.shに新しい名前 を引数にして実行すると関連するファイルを修正できます。
Sample
Legion of the Bouncy Castle を使ったSHA1とRSAの サンプルプログラム Sample
Legion of the Bouncy Castle を使ったYahoo!デベロッパーネットワークのOAuthの サンプルプログラム
JZLib を使ったGZIP処理の サンプルプログラム
このプログラムを作っていて気がついたのだがBAUMのHttpConnectionクラスは通信は 可能な場合はgzipで行っていてopenInputStream()は解凍されたデータが返ってきます。 microemulatorではgzipを使わずに通信を行っています。これらは上記のヘッダーを 見れば分かる事でした。microemulatorではHttpConnectionでAccept-Encodingをgzip にしてリクエストするとボディーにはgzipなデータが入ってきます。このときChunkな データの場合は、処理済み、具体的にはデータの長さを削除したRAWデータで渡され ます。JZLib 1.1.1はJava 1.3&MIDIP 2ではそのままコンパイルできずにコメントの 削除、Cloneの削除、無いエクセプション削除、java.ioのクラスの追加をして コンパイルしてあります。microemulatorでは600msくらいで処理できますがBAUMでは 11sもかかります。
Sample
kXML, XML Pull Parsing を使ったRSS処理の サンプルプログラム
Sample
org.json.me, を使った サンプルプログラム
Sample
RecordStoreをつかって端末に情報を保存する サンプルプログラム
オープンソースのUIライブラリーの Gear を使った サンプルプログラム
ビルドにはGear本体を同じフォルダーにコピーする必要があります。 ソフトキーを使えるようにいじっていたのだが、当初キーコードの問題と 思ってソースをいじったのだがうまく動かなかった。キーコード以前に どうもNokiaなどの携帯のVMのCommand処理とWillcomのJV-Lite2では違う動 きをするようだ。とりあえずあきらめて1キーと3キーをソフトキーの代わ りにするように処理を入れてある。Gearのメモ
Sample
月の満ち欠けの表示する プログラム
こちらもエンジン部分とは こちら のオープンソースを使っています。 それとここのコードも一部 利用させてもらいました。 国内の月のページ(The Moon Age Calendar) のデータと微妙な差があるので、エンジン部分のパラメータの調整が必要なのかも しれません。 グラフィック表示は簡易で正確でないかもしれません。 「日と月」 の 出没時刻は K.ShindoさんのアプレットのJAVAコード を利用させてもらいました。計算にはRealを使っています。それぞれのオープン ソースの出所はREADMEに書いてあります。
POM
FileConnectionをつかって端末に保存されているファイルリストを表示する サンプルプログラム
このサンプルはJSR75の機能を使っているのだが、MicroEmulatorでは動作 しなかった。MicroEmulatorの配布ファイルのlibディレクトリにmicroemu-jsr-75.jar が入っているので、設定すると使えるのかもしれないが調べていない。
端末がサポートしているエンコードを確認する サンプルプログラム
WX320KではUTF8とSJISだけがOKで他はNGになります。
ENCODE
MascotCapsuleを使ってモデルを表示する サンプルプログラム (J2ME_Planet.tgz)
HIのサンプルをベースにモデルの表示位置を変更して動かし、視点位置を 変更してモデルの大きさを変更しています。3Dプログラミング的には間違え ているような気もするが、なんとなく思ったように動いているので勘弁して ください。光源をいじって月の満ち欠けみたいな事をやってみたかったのだ が出来てません。リソースはmbacファイルのみでmtraファイルを使わずにモ デルを動かしています。上で書いたようにMacではモデルデータ(mbac)やア ニメーションデータ(mtra)を作る事は出来ないので、サンプルのモデルをそ のまま使っています。
MascotCapsuleで四角の面に色を貼ってY軸方向に回す サンプルプログラム
このサンプルはソニーエリクソンのサンプルコードを参考にしている。
第5使途ではないがMascotCapsuleで正八面体に色を貼ってY軸方向 に回す サンプルプログラム
このサンプルはソニーエリクソンのサンプルコードを参考にしている。
MascotCapsuleで四角の面にBMPのテクスチャーを貼ってY軸方向に回す サンプルプログラム
このサンプルはソニーエリクソンのサンプルコードを参考にしている。

リンク


Copyright (C) 2009 Hiroki Mori All Rights Reserved.