意識の移り変わり

最近よく聞く「意識が高い」とか知らない。それとは別のこと。

プログラムをぽちぽち書くに当たって最近ガラっと意識が変わってしまいました、というお話。

まずエディターは今更ながらVim、viでもいいやって感じです。別にSSHでサーバーに繋げてコンソールで操作するのが必須っていうわけでもないので、前まではVisual StudioやらEclipceやら、それこそもう ”THE 開発環境” という具合で、潤沢なメモリに強力なCPUを駆使し、おまけに馬鹿高いGPUなんぞ積んで開発を行うのは当たり前。

最近はですね、LinuxのCUIモードでぽちぽちやったり、ローカルのバーチャルマシンに入れたLinuxにわざわざSSHでアクセスしてコンソールでぽちぽちやってます。Windowsも捨ててDOSでもいいやっていう勢いです。

じゃあなぜそんな風に意識が変わったのかというと、最近GoogleがHTML5を駆使して作ったWeb絵本を出しました。

Google、ChromeチームがHTML5でつくった電子書籍
「20 Things I Learned about Browsers and the Web」
- MdN Design Interactive - Webデザインとグラフィックの総合情報サイト
http://www.mdn.co.jp/di/newstopics/15998/

20 Things I Learned About Browsers and the Web
http://www.20thingsilearned.com/ja-JP/home

カーソルキーやマウスでペラペラっとめくれる、Flash全盛期では当たり前のUIだけどこれをHTML5でやってみた、というさすがGoogle先生!なわけですよね。これ初めて見たとき僕は感動したんですよ。何に感動したかというと、僕は正直Webのことよく知らない。未だにDNSだとかIPアドレスのクラスだとか何やらさっぱりです。そういったものをWeb界の大先生Googleが、今をときめくHTML5を駆使して教えてくれるなんて素晴らしいじゃない!って思ったわけですよ。

UIも面白いけど、でもまあiPhoneだとかiPadをはじめとするタブレットの電子書籍では、技術は違えどペラペラっとめくるなんて当たり前なので特にUIに感動したってわけじゃなくて、HTML5 = iPadだとも思ってるし、どうせなら手持ちのiPadで通勤電車で読もうとワクワクしながら電車に乗ったんですよ奥さん。そうしたらですね、僕のiPad、おかしいんですかね、がっくがくで読めたもんじゃない。なので全然読んでないのでどんな内容なのか知らない。

ぱちん

ここで何かのスイッチが入れ替わっちゃったかもしれないです。

僕はPC歴は高々10年有るか無いかですが、それでも今までを振り返って、さんざんPCに投資して、それでもソフトウェアが必要とするメモリやCPUをはじめとするリソースは増大するばかり。Adobe・Apple・Microsoftを筆頭とするベンダーが出すアプリケーションに遅れを取らないようにPCを強化しても、あっという間に時代遅れ。正直疲れたわー。

いやいいんですよ、例えば最新CG技術を駆使したゲームは大好きだし、僕は音楽もやるのでクールなDAWだとか、絵描きさんならフォトショップやイラレは必須でしょう。そういった趣味や仕事に密接するものは投資する価値もあるってものです。でも普段の生活で使うようなちょっとしたエディタだとかブラウザだとか、そんなものにPCのリソース割きたくないです。Google先生のガクガクっぷりを見て幻滅気味です。

もう一つ意識の移り変わりの理由があって、まず愛用のデスクトップPCがとうとう再起不能になってしまいました。どうも3月の計画停電で繰り返しシャットダウンと通電を繰り返された結果だと睨んでるんですが、システムのHDDが壊れてしまって、過去10年あまりの大事なファイルもそこに入れっぱなしだったので全部なくなった;;
バックアップを怠った僕がいけないんですけどねははは。C言語勉強して初めて作ったアプリのソースだとか、一夜で要望に応えて組み上げたDLLだとか、出会いと別れの(笑)メール履歴やらなにやら、あーあ無くなっちゃった。一応、業者に頼んでリカバリしてもらうつもりですけれど。

そして、何か物が壊れる時って続くものです。今度は職場のPCまで逝かれて参りました。せっかく築き上げた快適開発環境は脆くも崩れ去るわけです。ははは。なんの呪いですかね。

それに今は節電節電、原発壊れて電車のクーラー効かないのに文句をいいながら原発反対運動週間。とか冗談を言いつつも不安は拭いきれないわけです。そんな中、800Wだー1000Wだーとか電源強化したりするのも、生真面目な僕(笑)にはできないわけでもある。

そういったことがあって、全てを捨てて一から始めたい気分になった、というのが正直なところ。だから開発機はなるべくしょぼいPCを使い、そういうPCでエレガントに動作するアプリケーションって素晴らしいよね、という意識です。

はははは、そりゃ無理だよ、って意見はもっともだとも思っていて、例えばNVIDIAのGPUプログラミングだとか、Flashの開発にはこれまた馬鹿高くてリソース食いのAdobeの開発環境がどうしても必要になってきますし、テスト駆動開発いわゆるTDDの手法は次々とビルドしながら書いていくもんだから、やっぱりそれなりのパワーは必要ではあります。他にも指摘しようと思えばいくらでも。けれどもじゃあ例えば5年前はどうしてたのっていう。幸い僕はその手の開発はやっていないので、何もいま馬鹿高い開発用PCを用意する必要性って今の僕には全然ないのですよね。せいぜい、そう、5年ぐらい前のPCで必要十分という今の私。

そんな意識の移り変わり。
いま、昔のしょっぽいPCを引っ張り出してきて、愛でてる。

すみません長くなりました。まとめるとVimってちょーべんりだよねって言いたかった。

あ、量子コンピュータだとかの新しいアーキテクチャが出たら飛びつきたいですね。まってる。

GTASA日本語化のしくみ…文字コードから座標を求める2

前回はGTASAで1バイトの文字からテクスチャ上の座標を割り出す仕組みを見てみました。
今回は日本語の2バイトでは、じゃあどうするのかを見てみます。

日本語用フォントテクスチャの用意

まず日本語化に当たってとても重要なのが、日本語のフォントを並べ立てたテクスチャを用意することです。
文字の表示にWindowsのリソースを使うような一般的なアプリなら要らないですが、GTASAは独自のフォントを使うのでこれが必要です。
これも元のフォントテクスチャにならって文字コードを順番に並べます。ASCIIコードも扱うためShift_JISです。

 

横幅2048ピクセル、縦幅1024ピクセル。
この大きさは必ず64とか128とか256とか2の階乗になっていなければだめです。
けっこう隙間があってやっつけ感が漂いますが、こうすると文字コードだけで座標が簡単に求まるのです。

テクスチャを見ると、左側は元のフォントテクスチャをそのまま使ってるのが分かると思います。
右側の日本語部分と大きさを揃えても良いのですが、せめて英数字だけは元の綺麗なフォントを使いたかったのがその理由です。

半角部分の文字の大きさはは横幅32ピクセル、縦幅40ピクセル、
全角部分は縦横16ピクセルの正方形です。
間違えました。16×20でした。

本来、日本代理店などがローカライズする場合は、必要最低限の文字だけを抜き出してぎゅうぎゅうに詰めて小さなリソースに収めたりします。流石ですね。

半角部分の座標計算

半角部分の大きさは元の大きさと変わらないのですが、
テクスチャの大きさが変わったので、このままじゃまともに表示できません。

前回の記事のソースコードでもあるように、0.0625などという係数が出てきました。
これはフォント横幅32ピクセルをテクスチャ横幅512ピクセルで割った数値でした。
この数値と、テクスチャをゼロから始まるグリッドに見立てた番号を掛け合わせると、
512ピクセルに対するそのグリッドの位置の割合が求められました。

グリッドが2番目なら:
0.0625*2=0.125
グリッド2番目は512ピクセルの0.125倍の位置。
512*0.125=64
64ピクセルの位置にグリッド2番目がある。

今回はテクスチャの大きさが変わったのでまずこの係数を変更します。
半角部分のフォントの大きさは元のままでテクスチャの横幅が2048になったので、32/2048で0.015625になります。
同じように計算すればしっかり64が求まるのが分かります。

これは横のXの位置についてでしたが、縦のYの位置についても同様です。
縦位置の係数は0.078125でした。フォントの縦幅が40ピクセルだからです。

これも同じように新しいテクスチャの縦幅1024から、40/1024=0.0390625となります。

前回示したGTASAのアセンブラコードのうち

00718B5A  |  FMUL DWORD PTR [858620]    ;  [858620h]の数値「0.0625」とX位置データ13.0を掛ける(13.0*0.0625=0.8125)


00718C37  |  FMUL QWORD PTR [872928]    ;  [872928h]の数値「0.078125」とY位置データ2.0を掛ける(2.0*0.078125=0.15625)

この二つが参照しているメモリアドレスのデータを直接変更すれば、
今回の新しいテクスチャで何事も無かったように半角英数字が表示できます。

メモリ書き換えの方法とかは本題じゃないので説明はまだ省きます。

全角部分の座標計算

全角部分は文字コード自体が今までと変わるので、
全て新しくルーチンを作る必要があります。

2バイトを読み込むルーチンはここでは置いておいて、
まずは2バイト文字コードから座標をどうやって計算するかを見てみます。

Shift_JISコードの並びを見てみるとこのようになっています。

8140h ——————– 819Fh
81A0h ————- 81FCh
8240h ——————– 829Fh
82A0h ————- 82FCh

テクスチャもこの文字コードの並びに対応させて作成します。

半角部分と同様にこの並びをグリッドと見立てて
それぞれが何番目になるのかを計算します。

半角では1バイトのうち上位4ビットと下位4ビットに分割して計算してましたが、
今回は2バイトあるので上位1バイトと下位1バイトに分けて、それぞれをX座標Y座標に置き換えます。

  • X座標を求める

横方向のX座標ですが、最初の行を見ると単純に文字コードの下位1バイトから40hを引けばゼロから数えることができるのですが、
テクスチャの左側には512ピクセルの空白地帯があるのでこれに合わせる必要があります。
全角フォントの横幅が16ピクセルなので、テクスチャ横幅2048ピクセルならグリッドが2048/16=128あることになります。
このうち横幅16ピクセルのグリッド32個分のグリッドが空白地帯なので、全角部分の左端はゼロではなく32(20h)にすればいいのです。
なので32(20h)を下位1バイトから引いてやります。

2行目をみると今度はA0hから始まっていますが、1行目の40hとの差(A0h-40h=60h)と
空白分の20hを足した80hを引けばいいことになります。
この変化は1行ごとにあるので、奇数行と偶数行で処理を分ければいいですね。

もし奇数行(40h~9Fの範囲)なら:
 40h-20h=20h…空白地帯のグリッド数が20h個なのでゼロと見なせる
もし偶数行(A0h以上)なら:
 A0h-80h=20h…同上

  • Y座標を求める

文字コード表を見ると、上位1バイトは2行ごとに変化してます。

8140h ——————– 819Fh
81A0h ————- 81FCh
8240h ——————– 829Fh
82A0h ————- 82FCh

81hから始まってるので81hを引いて2倍し、もし偶数行ならプラス1すれば、
これだけでY座標は求まります。

奇数行(下位バイトが40h~9Fhの範囲)なら:
 1行目…(81h-81h)*2=0
 3行目…(82h-81h)*2=2
偶数行(下位バイトがA0h以上)なら:
 2行目…(81h-81h)*2+1=1
 4行目…(82h-81h)*2+1=3

第二水準漢字になるとまた文字コードが飛びますが、
同じように計算させることはできます。

  • 係数

今までと同様に、係数とテクスチャの幅とグリッドの位置を掛け合わせれば座標が求まります。

Xの係数はフォントの幅16ピクセルにテクスチャの幅2048ピクセルなので

16/2048=0.0078125

となり、座標のピクセル値はグリッドゼロ番目なら

0.0078125*20h=0.25
2048*0.25=512ピクセル

などと計算できます。

Yの係数はフォントの高さ20ピクセルに対しテクスチャの縦幅1024なので

20/1024=0.01953125

となり、4行目(ゼロからなので[3番目]と数える)なら

0.01953125*3=0.05859375
1024*0.05859375=60ピクセル

となって座標を求めることができました。

以上

GTASAの日本語化のしくみとして、要点として文字コードから座標を求める説明&覚え書きですが、
あとはこれをコード化して対象プロセスに注入、などをします。

またもう一つの要点というか最大の要点と思いますが、日本語の2バイトを読み込むルーチンでしょうか。
ルーチン自体は単純なものなので書く必要もないかなとか思いますが、
暇があればそのうち書くかもしれないです。

GTASA日本語化のしくみ…文字コードから座標を求める1

GTASAの日本語化ローダーを作ってから約1年半、公開から1年ぐらい立ったですかね。
自分で作っておきながら内容が薄れて忘れそうなので記事を書いておきます。

日本語化ローダーの最大の要点としては、元々日本語マルチバイト文字に対応していないアプリケーションにメモリパッチを当てることでコードを書き換え、パラサイトルーチンを埋め込んで2バイト文字に対応するということですが、例えソースコードを読むにしても概念が分かってないと(忘れると)理解しがたいので今のうちに細かい点をメモしておきます。

細々とした処理の中で一番肝になるのは、文字コードとフォントテクスチャの座標との対応部分じゃないかなあと思います。
大きな一枚のテクスチャから望みの一文字を取り出すにはどうすればよいでしょうか。
GTASAはフォントテクスチャの中から一文字を取り出すのに、その文字コードを利用します。
この料理される文字コードがGTASAではASCIIコードの1バイトでしか対応していないので、日本語化としてはまずここをマルチバイト化するなどします。 がこれはまた別の話になります。

まずはGTASAのフォントテクスチャでの各フォントの並びを調べます。
フォントテクスチャの元の大きさは縦横512pxになっていて(ちなみにGTAIVでは拡大されて1024pxになってます)、
フォントがX軸の方向(横列)に16個、Y軸の方向(縦列)に13個並んでいます。

  

フォント一つの横幅は、512pxを16で割って32pxになります。もちろん画面に表示する際は32px固定ではなく、fonts.datで定義されたプロポーショナルデータを元に切り出すようです。ここではあくまでも一つ一つの座標の計算のための横幅32pxです。
縦幅はフォントの数が13個で割り切れませんが、12個目までは40pxで最後の一列だけが32pxとなっていますので40pxで計算して問題ありません。
縦幅はどうやら画面に表示される際でも固定のようです。

横に16個というのは何もいい加減に並べたわけではなく、ASCII文字コードが綺麗に16進数で0h~Fhまで並んでいることから来ています。
16個を並べれば、そのまま左から[0h]個目[Fh]個目と数えることができます。
そしてFhを超えたら二桁目が増えますが、増えた二桁目の分だけ一段下へ移動してまた左から同じように数えることが出来ます。
これによって文字コードそのものからテクスチャに升目を作ることが出来ますね。

 _______________________________________________________________
|20h|21h|22h|23h|24h|25h|26h|27h|28h|29h|2Ah|2Bh|2Ch|2Dh|2Eh|2Fh|
      !   "   #   $   %   &   '   (   )   *   +   ,   -   .   / 
_______________________________________________________________
|30h|31h|32h|33h|34h|35h|36h|37h|38h|39h|3Ah|3Bh|3Ch|3Dh|3Eh|3Fh|
  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
_______________________________________________________________
|40h|41h|42h|43h|44h|45h|46h|47h|48h|49h|4Ah|4Bh|4Ch|4Dh|4Eh|4Fh|
  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
...

もう一つ重要な点として、文字として表示できるASCIIコードは20h(半角スペース)から始まっていることです。
このままだと縦列はゼロから数えることが出来ませんね。
上の表でも20hから始まってますが、この20hという数値を文字コードから引けば縦列もゼロから数えることができるようになります。
上の表のようにASCII文字コードの順番で綺麗に並べると、次の例のように位置を求めることができます。

例:文字「M」を例にする。
「M」の文字コード4Dh。
20hを引いて2Dh。
上位4ビットの2hより、テクスチャの上から[2h]番目、
下位4ビットのDhより、テクスチャの左から[Dh]番目、
などと求めることが出来ます。

 _______________________________________________________________
|00h|01h|02h|03h|04h|05h|06h|07h|08h|09h|0Ah|0Bh|0Ch|0Dh|0Eh|0Fh|
      !   "   #   $   %   &   '   (   )   *   +   ,   -   .   / 
_______________________________________________________________
|10h|11h|12h|13h|14h|15h|16h|17h|18h|19h|1Ah|1Bh|1Ch|1Dh|1Eh|1Fh|
  0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
_______________________________________________________________
|20h|21h|22h|23h|24h|25h|26h|27h|28h|29h|2Ah|2Bh|2Ch|2Dh|2Eh|2Fh|
  @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
...                                                  ~~~

そして実際のテクスチャ座標はX座標が文字の横幅32pxにDh(13)を掛けて416px、Y座標は縦幅40pxに2h(2)を掛けて80pxとなるのが分かります。とてもシンプルですね。
ちなみにGTAIVだと効率化を求めたのか少し変わって、文字と位置の対応表をfonts.datに持っているようです。

実際にOllyDbgなどのデバッガで逆アセンブルされたGTASAのコードで、
文字「M」がどのように演算されて座標を求めるのかを見てみます。
このコードは相対アドレス 718B33h から始まります。以下に掲げるコードのうち数値は16進数です。
BLレジスタには既に「M」の文字コード4Dhから20hが引かれた「2Dh」が代入されている状態です。

—-

00718B33  |  MOV CL,BL                  ;  BLからCLに文字コードをコピー(CL=2Dh)
00718B35  |  SHR CL,4                   ;  4ビット右シフトしてY位置データが求まる(CL=02h)
00718B38  |  MOV AL,BL                  ;  ALに文字コードをコピー(AL=2Dh)
00718B3A  |  MOVZX EDX,CL               ;  EDXレジスタへY位置データを退避(EDX=02h)
00718B3D  |  AND AL,0F                  ;  Fマスクして下位4ビットを取り出しX位置データを求める(AL=Dh)
00718B3F  |  MOVZX ECX,AL               ;  ECXレジスタへX位置データをコピー(ECX=Dh)
00718B42  |  MOV EAX,[C71ACC]           ;  この例では関係ない
00718B47  |  TEST AX,AX
00718B4A  |  MOV [ESP+C],EDX            ;  FPU(浮動小数点数演算のプロセッサ)を使うためY位置データを準備
00718B4E  |  FILD DWORD PTR [ESP+C]     ;  Y位置データをFPUスタックへプッシュ(ST[0]=2.0)
00718B52  |  MOV [ESP+C],ECX            ;  X位置データを準備
00718B56  |  FILD DWORD PTR [ESP+C]     ;  X位置データをFPUスタックへプッシュ(ST[0]=13.0、ST[1]=2.0)
00718B5A  |  FMUL DWORD PTR [858620]    ;  [858620h]の数値「0.0625」とX位置データ13.0を掛ける(13.0*0.0625=0.8125)
00718B60  |  FSTP DWORD PTR [ESP+C]     ;  X位置の演算結果をスタック[ESP+C]へ保存する
00718B64  |  JE gta_sa.00718C37         ;  (多分)テクスチャの種類による条件でアドレス718C37hへジャンプ
・・・・・・
00718C37  |  FMUL QWORD PTR [872928]    ;  [872928h]の数値「0.078125」とY位置データ2.0を掛ける(2.0*0.078125=0.15625)
00718C3D  |  MOV AL,[ESP+7]             ;  ここでは関係ない
00718C41  |  TEST AL,AL

00718C43  |  FSTP DWORD PTR [ESP+8]     ;  Y位置の演算結果をスタック[ESP+8]へ保存する

—-

結果、[ESP+C]のスタックにはX位置データの演算結果 0.8125 が入りますが、試しにテクスチャの幅512で掛けると 512*0.8125=416 となり、実際に文字「M」はテクスチャのX座標416pxの位置にあってピッタリ一致します。
Y位置データ演算結果の[ESP+8]の 0.15625 も同様に512*0.15625=80となり、Y座標80pxの位置を見るとやっぱり文字「M」と一致します。

このように 0.0625 (フォントの幅32px/テクスチャ横幅512px) などのように乗算する数値をプロセスメモリの中にあらかじめ係数としてデータを持っていて、その係数をそのつど参照して計算しています。

C言語で簡単に書くとこうなるでしょうか。

—-

/**
* char a には1バイトの文字コードから0x20を減じたもを入れる
*/

void getTextCharCoordinate(char a, float *x, float *y)
{
    char b; // 1バイトのchar型なので日本語2バイトが入る余地は無い

    b = a & 0x0F; // 下位4ビットを取り出す
    *x = b * 0.0625; // X座標求まる
    b = a >> 4;        // 上位4ビットを取り出す
    *y = b * 0.078125; // Y座標求まる

}

—-

この後、細々とコードはまだまだ続きますが、今行った演算結果を元にして画面への表示位置やら文字と文字の間隔やら何やらを求めているようです。
上記のコードを見れば計算の元になるのがASCIIの1バイトのみで尚且つ専用テクスチャだけに対応しているのが分かり、日本語Shift-JISの2バイトを読み込んでも、まったくあさっての座標しか求まらず文字化けすることが分かるでしょう。こういった部分を2バイトに対応させて日本語化を行うことになります。

 

という感じで、GTASAのオリジナルがどうやってフォントテクスチャ座標と文字コードを紐付けてるのかの説明&覚え書きでした。

GXT Pad を更新してみた

GXT Pad はGTAのテキストを編集するツールです。久々に更新。 元々GTASA 専用に作ったのですが嬉しいことにGTA4でも読み込めるとか。 しかし起動して歓喜しようと思いきや強制終了しました。 にもかかわらず、みなさん普通に編集できるとか。不思議。中身的には確実にバッファオーバーフローしてるはずですよ。

なのでやはり強制終了する人もいるみたいです。
どうせ更新するならもう少し実装を進めてから、と考えてましたが、これは放っておけないので更新。

更新内容:
リストの文字列表示は260バイト以下に制限をかけた。

// リストへの文字列代入部分
lstrcpy(pItem->pszText, ownerdata[iItemIndx].value);
 ↓↓
// 更新内容
CString strtmp = ownerdata[iItemIndx].value; 
/* cchTextMax(260バイト)を超えるなら文字数をそれ以下にして表示させる */
lstrcpy(pItem->pszText, strtmp.Left(pItem->cchTextMax));

やろうと思ってまったく手を付けていない実装:

  • 置換:例えば車の名前などを一括で変えるなどできる。
  • マージ:例えば日本語化などをしたあと、リアルカーネームMODなどが入れられなくなるのでかなり必須機能だが実装は一筋縄ではない。
  • まともなアンドゥーリドゥー:結構な再設計が必要。
  • アイコンほしい・・・

—-
GXT Pad でテキストファイルを編集した後は、
gxt_jp_converterで変換しないとダメ文字で落ちますよ。

—-
2011年6月17日追記 上でGTA4でも読み込めるとありますが、現在はGTA4の仕様が変わり読み込めなくなってるはずです。これを使わずとも日本語化はできるので特に強い要望がなければ対応の予定はないです。

—-
(2014/02/18)ファイルへのリンク修正
(2017/08/23)ファイルへの再リンク修正

DatConverter

DatConverterがVistaで動かないらしい。
> Jane、Liveともログはユーザーフォルダのappdata\local\virtualstoreにあるのですが、そこを選択すると「すみませんが専用です」と出て選べません。
> Program Filesを選ぶと、動作はするのですがすべて変換に失敗してしまいます。。。
Program Files 決め打ちだったっけ?いやそんなはずはないお。
何年も前の実装なので覚えてないけど。ソースどこやったっけ。
そろそろVistaユーザーも増えてきてることだし、何か作るんならVista買って環境だけ持っておくべきだよなぁ。
WordPress.com で次のようなサイトをデザイン
始めてみよう