BD1ファイル解析情報
※データの無断転載は固くお断りします。
ファイルフォーマット概要
.bd1ファイルは、XOPSのマップデータを構成するファイルです。
X operations TOOLS ブロックエディタによれば、BD1の正式名称は"Block Data Version 1"です。
基本的には、「ブロック」と呼ばれる6面体と、そのテクスチャ情報が記録されています。
ファイルフォーマット詳細
ファイル構造
ファイル構造は以下の通りです。
ブロック数によってファイル全体のサイズは可変しますが、各要素の順序とデータ長は固定です。データの並び順はリトルエンディアンです。
[310Byte] テクスチャパス(31Byte×10枚) |
[2Byte] ブロック数 |
[316Byte×ブロック数] 個々のブロックデータ ・96Byte:頂点座標(xyz×8頂点) ・192Byte:テクスチャーUV指定(UV×6面) ・24Byte:テクスチャ番号(6面) ・4Byte:データ有効化フラグ |
テクスチャパス
マップで使用するテクスチャのファイルパスです。bd1ファイルからの相対パスで指定します。
一般的なASCIIで表現され、00(NULL)で終了とみなされます。テクスチャ1枚で31Byte未満の場合は、31Byteまで00(NULL)で埋めます。
ブロック数
マップのブロック数を表します。
本家XOPSの場合ブロック数は最大160個(0xA0)のため、2バイト目は常に0x00になります。
ブロックデータ
ブロックデータの実データを表します。前述のブロック数分、本ブロックデータを定義します。
●頂点座標
ブロック8頂点分の頂点座標を定義します。float型(4Byte)にて「最初にX軸 8座標分、次にY軸 8座標分、最後にZ軸 8座標分」で、計96Byteです。
(x,y,z x,y,z x,y,z ... ではなく、x,x,x,x... y,y,y,y... z,z,z,z... で格納されています。)
なお座標軸は左手系座標で、X-Z平面が水平 Y軸が高さです。
8頂点の格納順序は以下の通りです。
▲ブロックの頂点格納順序
上4点(0–3)+下4点(4–7)のデータ順であり、座標の位置関係は以下の通りとなります。
※ブロック全体が回転している場合、その限りではありません。
・0:x-, y+, z-
・1:x+, y+, z-
・2:x+, y+, z+
・3:x-, y+, z+
・4:x-, y-, z-
・5:x+, y-, z-
・6:x+, y-, z+
・7:x-, y-, z+
●テクスチャーUV指定
テクスチャーのUV座標を6面分指定します。float型(4Byte)を用いて、1面の4隅のU座標を4個×6面、次にV座標を4個×6面、合計192Byteになります。
前述の頂点座標を元に、以下の頂点順序・構成で面を生成します。
1、[1,0,3,2]
2、[6,7,4,5]
3、[5,4,0,1]
4、[6,5,1,2]
5、[7,6,2,3]
6、[4,7,3,0]
●テクスチャ番号
テクスチャ番号をint型の4Byteで6面分指定します。ただしデータの有効範囲は00~09のため、2~4バイト目は常に0x00になります。
●データ有効化フラグ
本ブロックデータ(1個分)のデータ有効化フラグを表します。int型(4Byte)で表現され、ゲームとエディタで挙動が異なります。
本家エディタ:0の場合はエディタ上で表示されず、1以上で表示されます。
ゲーム本体:データ有効化フラグは無意味です。
【参考】JSONによるフォーマット記述メタデータ
{ "format": "BD1", "long_name": "Block Data Version 1", "version": 1, "endianness": "LE", "coordinate_system": { "handedness": "left", "axes": "X-Z horizontal, Y up" }, "file_structure": { "header": { "size": 310, "texture_paths": { "count": 10, "entry_size": 31, "encoding": "ASCII-NULL", "path_relative": true } }, "block_count": { "offset": 310, "size": 2, "type": "uint16_le", "note": "Maximum 160 blocks" }, "blocks": { "count_ref": "block_count", "record_size": 316, "layout": ["vertices", "uv", "texture_index", "enable_flag"] } }, "block_layout": { "vertices": { "size": 96, "type": "float32_le", "vertex_count": 8, "vertex_order": "X8Y8Z8" }, "uv": { "size": 192, "type": "float32_le", "order": "U4×6faces then V4×6faces", "per_face_corners": 4, "faces": 6 }, "texture_index": { "size": 24, "type": "int32_le", "faces": 6, "valid_range": [0, 9] }, "enable_flag": { "size": 4, "type": "int32_le", "usage": "reserved" } }, "faces": { "build_order": [ [1, 0, 3, 2], [6, 7, 4, 5], [5, 4, 0, 1], [6, 5, 1, 2], [7, 6, 2, 3], [4, 7, 3, 0] ], "labels": { "f0": { "name": "top", "axis": "Y+" }, "f1": { "name": "bottom", "axis": "Y-" }, "f2": { "name": "front", "axis": "Z-" }, "f3": { "name": "right", "axis": "X+" }, "f4": { "name": "back", "axis": "Z+" }, "f5": { "name": "left", "axis": "X-" } } } } |