VGO 2.0 のファイル仕様

# 1. ファイル仕様

このページではVGO 2.0 のファイル仕様についての解説を行います。

## 目次

- [全体目次] (https://qiita.com/izayoijiichan/items/5c7004cd87fe31a08414)
  - 1. ファイル仕様（現在位置）
  - [2. データ スキーマ] (https://qiita.com/izayoijiichan/items/0eb1c5c2bd2b4a063fa2)

## 1-1. ファイル拡張子

VGOに関係するファイルの拡張子は以下の3種類が存在します。

|拡張子|説明|必要|
|:--:|:--|:--:|
|.vgo|VGOファイルです。|必要|
|.vgk|暗号化したVGOファイルを復号するためのキーファイルです。|任意|
|(.bin)|リソース ファイルです。|任意|

暗号化も分割もされていない通常の場合は`.vgo`のみになります。


## 1-2. チャンク

VGO 2.0 のフォイルフォーマットではベースにIFFチャンクを採用しています。
IFFチャンクはタイプID、データ長、データの３つの要素で構成されます。

|オフセット|バイト サイズ|名前|
|:--:|:--:|:--|
|0|4|タイプID|
|4|4|データ長|
|8|n|データ|

チャンクのバイトサイズは偶数となるようデータの調整を行います。
奇数となる場合にはデータ部に1byteのパディングを付与します。
結果としてデータ長は必ず偶数となります。


## チャンク グループ

VGO 2.0 ではヘッダーも含めると、およそ8つのチャンクグループによりファイルを構成しています。
（ヘッダーもチャンクの一部です）

|タイプ グループ|名前|説明|必須|
|:--|:--|:--|:--:|
|VGO|ヘッダー|ファイル ヘッダーです。|true|
|IDX|インデックス|チャンクのインデックスを保持します。|true|
|COMP|コンポーザー|3Dモデルを構築するための構成を保持します。|true|
|AIXX|アセット情報|アセット情報を保持します。|true|
|LAXX|レイアウト情報|3Dモデルのレイアウト情報を保持します。|true|
|RAXX|リソース アクセサー|リソースへのアクセス情報を保持します。|true|
|REXX|リソース|リソースを保持します。|true|
|CXXX|暗号情報|暗号情報を保持します。||


## チャンク タイプID

VGO 2.0 で定義しているチャンク タイプIDの一覧です。

|タイプID|16進数表記|名前|plain/crypt|データ フォーマット|
|:--|:--:|:--|:--:|:--:|
|VGO|0x004F4756|ファイル マジックです。|plain|binary|
|IDX|0x00584449|インデックス チャンクです。|plain|binary|
|COMP|0x504D4F43|コンポーザーです。|plain|binary|
|AIPJ|0x4A504941|アセット情報です。|plain|JSON|
|AIPB|0x42504941|アセット情報です。|plain|BSON|
|LAPJ|0x4A50414C|レイアウト情報です。|plain|JSON|
|LAPB|0x4250414C|レイアウト情報です。|plain|BSON|
|RAPJ|0x4A504152|リソース アクセサー情報です。|plain|JSON|
|RAPB|0x42504152|リソース アクセサー情報です。|plain|BSON|
|RACJ|0x4A434152|リソース アクセサー情報です。|crypt|JSON|
|RACB|0x42434152|リソース アクセサー情報です。|crypt|BSON|
|CRAJ|0x4A415243|リソース アクセサーの暗号情報です。|plain|JSON|
|CRAB|0x42415243|リソース アクセサーの暗号情報です。|plain|BSON|
|REPb|0x62504552|リソースです。|plain|binary|
|REPJ|0x4A504552|リソースです。|plain|JSON|
|REPB|0x42504552|リソースです。|plain|BSON|


## 各チャンクの解説

データフォーマットをJSON、暗号化なし、リソースはバイナリーという基本構成の場合で説明を行います。


### ヘッダー チャンク

ファイルの先頭0バイト目からはヘッダーチャンクになります。
チャンクサイズは16バイトです。（データ部は8バイトになります）

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--|
|0|4|unsigned int|Magic|ファイル マジックです。|true|VGO|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|8|
|8|1|unsigned byte|MajorVersion|VGOのメジャー バージョンです。|true|2|
|9|1|unsigned byte|MinorVersion|VGOのマイナー バージョンです。|true|0|
|10|1|unsigned byte|GeometryCoordinate|座標系です。|true|1: 右手系<br>2: 左手系|
|11|1|unsigned byte|UVCoordinate|UVコーディネートです。|true|1: Top Left<br>2: Bottom Left|
|12|1|unsigned byte|IsCrypted|リソース アクセサーが暗号化されているかどうか。|true|0: 暗号化されていない<br>1: 暗号化されている|
|13|1|unsigned byte|IsRequireExternalCryptKey|リソース アクセサーが外部暗号キーを必要とするかどうか。|true|0: 不要<br>1: 必要|
|14|1|unsigned byte|(Reserved)||||
|15|1|unsigned byte|(Reserved)||||

先頭4バイトはファイルマジックです。
`VGO`固定となります。（正確には`"VGO "`となります。）
16進数で表すと`0x004F4756`となります。

MajorVersion は VGOの仕様のメジャーバージョンです。`2`で固定となります。
MinorVersion は VGOの仕様のマイナーバージョンです。

GeometryCoordinate は座標系です。
レイアウト情報やリソースに含まれるデータが右手系なのか左手系なのかを、この値を見て判断します。

UVCoordinate はUVコーディネートです。
レイアウト情報やリソースに含まれるUVデータの起点位置を、この値を見て判断します。

IsCrypted はリソース アクセサーが暗号化されているかどうかです。
1の場合はリソース アクセサーが暗号化されていることを意味します。

IsRequireExternalCryptKey はリソース アクセサーが外部暗号キーを必要とするかどうかです。
1の場合は3Dモデルを復元するために暗号キー（復号キー）を必要とします。
0の場合は暗号キーが不要もしくはファイル内にキーが埋め込まれています。


### インデックス チャンク

インデックス チャンクは、ファイル内で使用されているチャンクと開始位置等を保持しています。

例えるなら、本でいうところの目次と同じような役割を持ちます。


|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|IDX|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true||
|8|16 * n|VgoIndexChunkDataElement[]||チャンク インデックス情報です。|true||

データ部はインデックス チャンク データ エレメントの配列になります。

仕様
- インデックスチャンクはファイルの先頭の16バイト目からはじまります。
- エレメントににはヘッダーチャンク情報とインデックスチャンク情報は含めません。

基本構成の場合、`COMP`, `AIPJ`, `LAPJ`, `RAPJ`, `REPb` の5つのチャンクが定義されます。


#### インデックス チャンク データ エレメント

VgoIndexChunkDataElement

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|ChunkTypeId|チャンク タイプIDです。|true||
|4|4|unsigned int|ByteOffset|チャンクの開始位置を示します。|true||
|8|4|unsigned int|ByteLength|チャンクの合計サイズです。（パディング分を含みます）|true||
|12|1|unsigned byte|BytePadding|チャンクデータのパディングのバイト数です。|true|0 or 1|
|13|1|unsigned byte|(Reserved)||||
|14|1|unsigned byte|(Reserved)||||
|15|1|unsigned byte|(Reserved)||||


### コンポーザー チャンク

3Dモデルの構成を示すチャンクです。

チャンクの開始位置はインデックス チャンクのコンポーザー チャンク情報から探します。

チャンク サイズは40バイトになります。
（データサイズは32バイトになります）

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|COMP|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|32|
|8|32|VgoComponentChunkData|||true||

#### コンポーザー チャンク データ

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|AssetInfoChunkTypeId|アセット情報 チャンク タイプIDです。|true|AIXX|
|4|4|unsigned int|(Reserved)||||
|8|4|unsigned int|LayoutChunkTypeId|レイアウト チャンク タイプIDです。|true|LAXX|
|12|4|unsigned int|(Reserved)||||
|16|4|unsigned int|ResourceAccessorChunkTypeId|リソース アクセサー チャンク タイプIDです。|true|RAXX|
|20|4|unsigned int|ResourceAccessorCryptChunkTypeId|リソース アクセサー 暗号 チャンク タイプIDです。|false|CRAX|
|24|4|unsigned int|ResourceChunkTypeId|リソース チャンク タイプIDです。|true|REXX|
|28|4|unsigned int|(Reserved)||||

基本構成の場合
AssetInfoChunkTypeId は `AIPJ`
LayoutChunkTypeId は `LAPJ`
ResourceAccessorChunkTypeId は `RAPJ`
ResourceAccessorCryptChunkTypeId は (None)
ResourceChunkTypeId は `REPb`
となります。


### アセット情報 チャンク

チャンクの開始位置はインデックス チャンクのアセット チャンク情報から探します。

8 + n byte

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|AIXX|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|n|
|8|n|byte[]|Data|アセット情報。|true|JSON or BSON|

基本構成の場合はチャンクタイプIDは`AIPJ`で、データはJSONデータです。


### レイアウト チャンク

チャンクの開始位置はインデックス チャンクのレイアウト チャンク情報から探します。

チャンク サイズは 8 + n バイトになります。

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|LAXX|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|n|
|8|n|byte[]|Data|レイアウト データ。|true|JSON or BSON|

基本構成の場合はチャンクタイプIDは`LAPJ`で、データはJSONデータです。


### リソース アクセサー チャンク

チャンクの開始位置はインデックス チャンクのリソース アクセサー チャンク情報から探します。

チャンク サイズは 8 + n バイトになります。

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|RAXX|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|n|
|8|n|byte[]|Data|リソース アクセサー データ。|true|JSON or BSON (plain or crypted)|

基本構成の場合はチャンクタイプIDは`RAPJ`で、データは暗号化なしのJSONデータです。


### リソース チャンク

チャンクの開始位置はインデックス チャンクのリソース チャンク情報から探します。

チャンク サイズは 8 + n バイトになります。

|オフセット|バイト サイズ|データ タイプ|名前|説明|必須|値|
|:--:|:--:|:--:|:--|:--|:--:|:--:|
|0|4|unsigned int|TypeId|チャンク タイプIDです。|true|REXX|
|4|4|unsigned int|DataLength|チャンク データのサイズです。|true|n|
|8|n|byte[]|Data|リソース データ。|true|binary or JSON or BSON|

基本構成の場合はチャンクタイプIDは`REPb`で、データはバイナリーデータです。

リソースは画像、ノード位置、メッシュ、スキンなどのデータを含んでいます。


## 1-3. データ フォーマット

VGO 2.0 のデータフォーマットは`JSON`、`BSON`、`binary`に分類されます。

|タイプ|名前|
|:--:|:--|
|JSON|JSON|
|BSON|BSON|
|binary|バイナリー|

`JSON`の場合にはデータをJSONでデシリアライズすることで元のデータに復元することができます。
`BSON`の場合にはデータをBSONでデシリアライズすることで元のデータに復元することができます。
`binary`（リソース）の場合にはリソース アクセサーを使用することでデータを抽出することができます。

## 目次

- [全体目次] (https://qiita.com/izayoijiichan/items/5c7004cd87fe31a08414)
  - 1. ファイル仕様（現在位置）
  - [2. データ スキーマ] (https://qiita.com/izayoijiichan/items/0eb1c5c2bd2b4a063fa2)