/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 表示枠リスト 読み込む(Stream fs, PMXヘッダ header) { int 表示枠数 = ParserHelper.get_Int(fs); Debug.WriteLine($"表示枠数: {表示枠数}"); var list = new 表示枠リスト(表示枠数); for (int i = 0; i < 表示枠数; i++) { list.Add(表示枠.読み込む(fs, header)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static ボーンリスト 読み込む(FileStream fs, PMXヘッダ header) { int ボーン数 = ParserHelper.get_Int(fs); Debug.WriteLine($"ボーン数: {ボーン数}"); var list = new ボーンリスト(ボーン数); for (int i = 0; i < ボーン数; i++) { list.Add(ボーン.読み込む(fs, header)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 材質リスト 読み込む(FileStream fs, PMXヘッダ header) { int 材質数 = ParserHelper.get_Int(fs); Debug.WriteLine($"材質数: {材質数}"); var list = new 材質リスト(材質数); for (int i = 0; i < 材質数; i++) { list.Add(材質.読み込む(fs, header)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static モーフリスト 読み込む(FileStream fs, PMXヘッダ header) { int モーフ数 = ParserHelper.get_Int(fs); Debug.WriteLine($"モーフ数: {モーフ数}"); var list = new モーフリスト(モーフ数); for (int i = 0; i < モーフ数; i++) { list.Add(モーフ.読み込む(fs, header)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static テクスチャリスト 読み込む(FileStream fs, PMXヘッダ header) { int テクスチャ数 = ParserHelper.get_Int(fs); Debug.WriteLine($"テクスチャ数: {テクスチャ数}"); var list = new テクスチャリスト(テクスチャ数); for (int i = 0; i < テクスチャ数; i++) { list.Add(ParserHelper.get_TextBuf(fs, header.エンコード方式)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static ジョイントリスト 読み込む(Stream fs, PMXヘッダ header) { int ジョイント数 = ParserHelper.get_Int(fs); Debug.WriteLine($"ジョイント数: {ジョイント数}"); var list = new ジョイントリスト(ジョイント数); for (int i = 0; i < ジョイント数; i++) { list.Add(ジョイント.読み込む(fs, header)); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 剛体リスト 読み込む(Stream fs, PMXヘッダ header) { int 剛体数 = ParserHelper.get_Int(fs); Debug.WriteLine($"剛体数: {剛体数}"); var list = new 剛体リスト(剛体数); for (int i = 0; i < 剛体数; i++) { list.Add(剛体.読み込む(fs, header)); } return(list); }
} // 角度制限あり の場合 /// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static IKリンク 読み込む(FileStream fs, PMXヘッダ header) { var ikLinkData = new IKリンク(); ikLinkData.リンクボーンのボーンインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); ikLinkData.角度制限あり = ParserHelper.get_Byte(fs) == 1 ? true : false; if (ikLinkData.角度制限あり) { ikLinkData.角度制限の下限rad = ParserHelper.get_Float3(fs); ikLinkData.角度制限の上限rad = ParserHelper.get_Float3(fs); } return(ikLinkData); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 材質 読み込む(FileStream fs, PMXヘッダ header) { var material = new 材質(); material.材質名 = ParserHelper.get_TextBuf(fs, header.エンコード方式); material.材質名_英 = ParserHelper.get_TextBuf(fs, header.エンコード方式); material.拡散色 = ParserHelper.get_Float4(fs); material.反射色 = ParserHelper.get_Float3(fs); material.反射強度 = ParserHelper.get_Float(fs); material.環境色 = ParserHelper.get_Float3(fs); material.描画フラグ = (描画フラグ)ParserHelper.get_Byte(fs); material.エッジ色 = ParserHelper.get_Float4(fs); material.エッジサイズ = ParserHelper.get_Float(fs); material.通常テクスチャの参照インデックス = ParserHelper.get_Index(fs, header.テクスチャインデックスサイズ); material.スフィアテクスチャの参照インデックス = ParserHelper.get_Index(fs, header.テクスチャインデックスサイズ); switch (ParserHelper.get_Byte(fs)) { case 0: material.スフィアモード = スフィアモード.無効; break; case 1: material.スフィアモード = スフィアモード.乗算; break; case 2: material.スフィアモード = スフィアモード.加算; break; case 3: material.スフィアモード = スフィアモード.サブテクスチャ; break; default: throw new InvalidDataException("スフィアモード値が異常です。"); } material.共有Toonフラグ = ParserHelper.get_Byte(fs); material.共有Toonのテクスチャ参照インデックス = material.共有Toonフラグ == 0 ? ParserHelper.get_Index(fs, header.テクスチャインデックスサイズ) : ParserHelper.get_Byte(fs); material.メモ = ParserHelper.get_TextBuf(fs, header.エンコード方式); material.頂点数 = ParserHelper.get_Int(fs); if (material.頂点数 % 3 != 0) { throw new InvalidDataException(); // 3 の倍数じゃなければエラー。 } return(material); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 枠内要素 読み込む(Stream fs, PMXヘッダ header) { var data = new 枠内要素(); data.要素対象 = (ParserHelper.get_Byte(fs) == 1); if (data.要素対象) { data.要素対象インデックス = ParserHelper.get_Index(fs, header.モーフインデックスサイズ); } else { data.要素対象インデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); } return(data); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 表示枠 読み込む(Stream fs, PMXヘッダ header) { var data = new 表示枠(); data.枠名 = ParserHelper.get_TextBuf(fs, header.エンコード方式); data.枠名_英 = ParserHelper.get_TextBuf(fs, header.エンコード方式); data.特殊枠フラグ = ParserHelper.get_Byte(fs) == 1; int 枠内要素数 = ParserHelper.get_Int(fs); data.枠内要素リスト = new List <枠内要素>(枠内要素数); for (int i = 0; i < 枠内要素数; i++) { data.枠内要素リスト.Add(枠内要素.読み込む(fs, header)); } return(data); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 面リスト 読み込む(FileStream fs, PMXヘッダ header) { int 面数 = ParserHelper.get_Int(fs); Debug.WriteLine($"面数: {面数 / 3}"); var list = new 面リスト(面数 / 3); for (int i = 0; i < 面数 / 3; i++) { list.Add( new 面( ParserHelper.get_VertexIndex(fs, header.頂点インデックスサイズ), ParserHelper.get_VertexIndex(fs, header.頂点インデックスサイズ), ParserHelper.get_VertexIndex(fs, header.頂点インデックスサイズ))); } return(list); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static PMXヘッダ 読み込む(FileStream fs) { var header = new PMXヘッダ(); // マジックナンバー("PMX "の4バイト)の読み取り var MagicNumberbuf = new byte[4]; fs.Read(MagicNumberbuf, 0, 4); if (Encoding.Unicode.GetString(MagicNumberbuf, 0, 4) != "PMX " && Encoding.UTF8.GetString(MagicNumberbuf, 0, 4) != "PMX ") { throw new InvalidDataException("PMXファイルのマジックナンバーが間違っています。ファイルが破損しているか、対応バージョンではありません。"); } // バージョン情報の読み取り header.PMXバージョン = ParserHelper.get_Float(fs); // 後のデータ列のバイト列 if (ParserHelper.get_Byte(fs) != 8) { throw new NotImplementedException(); // PMX2.0 は 8 で固定 } byte[] descriptionbuf = new byte[8]; // 詳細のデータ(8バイト固定) fs.Read(descriptionbuf, 0, 8); header.エンコード方式 = descriptionbuf[0] == 1 ? EncodeType.UTF8 : EncodeType.UTF16LE; header.追加UV数 = descriptionbuf[1]; header.頂点インデックスサイズ = descriptionbuf[2]; header.テクスチャインデックスサイズ = descriptionbuf[3]; header.材質インデックスサイズ = descriptionbuf[4]; header.ボーンインデックスサイズ = descriptionbuf[5]; header.モーフインデックスサイズ = descriptionbuf[6]; header.剛体インデックスサイズ = descriptionbuf[7]; return(header); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> public static PMXモデル 読み込む(FileStream fs) { var model = new PMXモデル(); model.ヘッダ = PMXヘッダ.読み込む(fs); model.モデル情報 = PMXモデル情報.読み込む(fs, model.ヘッダ); model.頂点リスト = 頂点リスト.読み込む(fs, model.ヘッダ); model.面リスト = 面リスト.読み込む(fs, model.ヘッダ); model.テクスチャリスト = テクスチャリスト.読み込む(fs, model.ヘッダ); model.材質リスト = 材質リスト.読み込む(fs, model.ヘッダ); model.ボーンリスト = ボーンリスト.読み込む(fs, model.ヘッダ); model.モーフリスト = モーフリスト.読み込む(fs, model.ヘッダ); model.表示枠リスト = 表示枠リスト.読み込む(fs, model.ヘッダ); model.剛体リスト = 剛体リスト.読み込む(fs, model.ヘッダ); model.ジョイントリスト = ジョイントリスト.読み込む(fs, model.ヘッダ); if (model.ヘッダ.PMXバージョン >= 2.1) { // Todo: SoftBody の読み込みは未対応 //model.SoftBodyデータリスト = SoftBodyリスト.読み込む( fs, model.ヘッダ ); } return(model); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 剛体 読み込む(Stream fs, PMXヘッダ header) { var data = new 剛体(); data.剛体名 = ParserHelper.get_TextBuf(fs, header.エンコード方式); data.剛体名_英 = ParserHelper.get_TextBuf(fs, header.エンコード方式); data.関連ボーンインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); data.グループ = ParserHelper.get_Byte(fs); data.非衝突グループフラグ = ParserHelper.get_UShort(fs); data.形状 = (剛体形状)ParserHelper.get_Byte(fs); data.サイズ = ParserHelper.get_Float3(fs); data.位置 = ParserHelper.get_Float3(fs); data.回転rad = ParserHelper.get_Float3(fs); data.質量 = ParserHelper.get_Float(fs); data.移動減衰 = ParserHelper.get_Float(fs); data.回転減衰 = ParserHelper.get_Float(fs); data.反発力 = ParserHelper.get_Float(fs); data.摩擦力 = ParserHelper.get_Float(fs); data.物理演算 = (剛体の物理演算)ParserHelper.get_Byte(fs); return(data); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static モーフ 読み込む(FileStream fs, PMXヘッダ header) { var morph = new モーフ(); morph.モーフオフセットリスト = new List <モーフオフセット>(); morph.モーフ名 = ParserHelper.get_TextBuf(fs, header.エンコード方式); morph.モーフ名_英 = ParserHelper.get_TextBuf(fs, header.エンコード方式); morph.操作パネル = ParserHelper.get_Byte(fs); byte Morphtype = ParserHelper.get_Byte(fs); morph.モーフオフセット数 = ParserHelper.get_Int(fs); for (int i = 0; i < morph.モーフオフセット数; i++) { switch (Morphtype) { case 0: //Group Morph morph.モーフ種類 = モーフ種類.グループ; morph.モーフオフセットリスト.Add(グループモーフオフセット.読み込む(fs, header)); break; case 1: //Vertex Morph morph.モーフ種類 = モーフ種類.頂点; morph.モーフオフセットリスト.Add(頂点モーフオフセット.読み込む(fs, header)); break; case 2: morph.モーフ種類 = モーフ種類.ボーン; morph.モーフオフセットリスト.Add(ボーンモーフオフセット.読み込む(fs, header)); break; //3~7はすべてUVMorph case 3: morph.モーフ種類 = モーフ種類.UV; morph.モーフオフセットリスト.Add(UVモーフオフセット.読み込む(fs, header, モーフ種類.UV)); break; case 4: morph.モーフ種類 = モーフ種類.追加UV1; morph.モーフオフセットリスト.Add(UVモーフオフセット.読み込む(fs, header, モーフ種類.追加UV1)); break; case 5: morph.モーフ種類 = モーフ種類.追加UV2; morph.モーフオフセットリスト.Add(UVモーフオフセット.読み込む(fs, header, モーフ種類.追加UV2)); break; case 6: morph.モーフ種類 = モーフ種類.追加UV3; morph.モーフオフセットリスト.Add(UVモーフオフセット.読み込む(fs, header, モーフ種類.追加UV3)); break; case 7: morph.モーフ種類 = モーフ種類.追加UV4; morph.モーフオフセットリスト.Add(UVモーフオフセット.読み込む(fs, header, モーフ種類.追加UV4)); break; case 8: //Material Morph morph.モーフ種類 = モーフ種類.材質; morph.モーフオフセットリスト.Add(材質モーフオフセット.読み込む(fs, header)); break; case 9: if (header.PMXバージョン < 2.1) { throw new InvalidDataException("FlipモーフはPMX2.1以降でサポートされています。"); } morph.モーフ種類 = モーフ種類.フリップ; morph.モーフオフセットリスト.Add(フリップモーフオフセット.読み込む(fs, header)); break; case 10: if (header.PMXバージョン < 2.1) { throw new InvalidDataException("ImpulseモーフはPMX2.1以降でサポートされています。"); } morph.モーフ種類 = モーフ種類.インパルス; morph.モーフオフセットリスト.Add(インパルスモーフオフセット.読み込む(fs, header)); break; } } return(morph); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static 頂点 読み込む(FileStream fs, PMXヘッダ header) { var vertex = new 頂点(); vertex.位置 = ParserHelper.get_Float3(fs); vertex.法線 = ParserHelper.get_Float3(fs); vertex.UV = ParserHelper.get_Float2(fs); vertex.追加UV = new Vector4[header.追加UV数]; for (int i = 0; i < header.追加UV数; i++) { vertex.追加UV[i] = ParserHelper.get_Float4(fs); } switch ((BoneWeight.形方式)ParserHelper.get_Byte(fs)) { case BoneWeight.形方式.BDEF1: vertex.ウェイト変形方式 = BoneWeight.形方式.BDEF1; vertex.ボーンウェイト = new BoneWeight.BDEF1() { boneReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), }; break; case BoneWeight.形方式.BDEF2: vertex.ウェイト変形方式 = BoneWeight.形方式.BDEF2; vertex.ボーンウェイト = new BoneWeight.BDEF2() { Bone1ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone2ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone1Weight = ParserHelper.get_Float(fs), }; break; case BoneWeight.形方式.BDEF4: vertex.ウェイト変形方式 = BoneWeight.形方式.BDEF4; vertex.ボーンウェイト = new BoneWeight.BDEF4() { Bone1ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone2ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone3ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone4ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Weights = ParserHelper.get_Float4(fs), }; break; case BoneWeight.形方式.SDEF: vertex.ウェイト変形方式 = BoneWeight.形方式.SDEF; vertex.ボーンウェイト = new BoneWeight.SDEF() { Bone1ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone2ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone1Weight = ParserHelper.get_Float(fs), SDEF_C = ParserHelper.get_Float3(fs), SDEF_R0 = ParserHelper.get_Float3(fs), SDEF_R1 = ParserHelper.get_Float3(fs), }; break; case BoneWeight.形方式.QDEF: if (header.PMXバージョン < 2.1f) { throw new InvalidDataException("QDEFはPMX2.1以降でのみサポートされます。"); } vertex.ウェイト変形方式 = BoneWeight.形方式.QDEF; vertex.ボーンウェイト = new BoneWeight.QDEF() { Bone1ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone2ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone3ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Bone4ReferenceIndex = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ), Weights = ParserHelper.get_Float4(fs), }; break; default: throw new InvalidDataException(); } vertex.エッジ倍率 = ParserHelper.get_Float(fs); return(vertex); }
/// <summary> /// 指定されたストリームから読み込む。 /// </summary> internal static ボーン 読み込む(FileStream fs, PMXヘッダ header) { var bone = new ボーン(); bone.IKリンクリスト = new List <IKリンク>(); bone.ボーン名 = ParserHelper.get_TextBuf(fs, header.エンコード方式); bone.ボーン名_英 = ParserHelper.get_TextBuf(fs, header.エンコード方式); bone.位置 = ParserHelper.get_Float3(fs); bone.親ボーンのインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); bone.形階層 = ParserHelper.get_Int(fs); var flag = new byte[2]; flag[0] = ParserHelper.get_Byte(fs); flag[1] = ParserHelper.get_Byte(fs); Int16 flagnum = BitConverter.ToInt16(flag, 0); bone.ボーンの接続先表示方法 = ParserHelper.isFlagEnabled(flagnum, 0x0001) ? E接続先表示方法.ボーンで指定 : E接続先表示方法.相対座標で指定; bone.回転可能である = ParserHelper.isFlagEnabled(flagnum, 0x0002); bone.移動可能である = ParserHelper.isFlagEnabled(flagnum, 0x0004); bone.表示可能である = ParserHelper.isFlagEnabled(flagnum, 0x0008); bone.操作可能である = ParserHelper.isFlagEnabled(flagnum, 0x0010); bone.IKボーンである = ParserHelper.isFlagEnabled(flagnum, 0x0020); bone.ローカル付与対象 = ParserHelper.isFlagEnabled(flagnum, 0x0080) ? Eローカル付与対象.親のローカル変形量 : Eローカル付与対象.ユーザ変形値_IKリンク_多重付与; bone.回転付与される = ParserHelper.isFlagEnabled(flagnum, 0x0100); bone.移動付与される = ParserHelper.isFlagEnabled(flagnum, 0x0200); bone.回転軸あり = ParserHelper.isFlagEnabled(flagnum, 0x0400); bone.ローカル軸あり = ParserHelper.isFlagEnabled(flagnum, 0x0800); bone.物理後変形である = ParserHelper.isFlagEnabled(flagnum, 0x1000); bone.外部親変形である = ParserHelper.isFlagEnabled(flagnum, 0x2000); if (bone.ボーンの接続先表示方法 == E接続先表示方法.相対座標で指定) { bone.ボーン位置からの相対位置 = ParserHelper.get_Float3(fs); } else { bone.接続先ボーンのボーンインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); } if (bone.回転付与される || bone.移動付与される) { bone.付与親ボーンインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); bone.付与率 = ParserHelper.get_Float(fs); } if (bone.回転軸あり) { bone.回転軸の方向ベクトル = ParserHelper.get_Float3(fs); } if (bone.ローカル軸あり) { bone.ローカル軸のX軸の方向ベクトル = ParserHelper.get_Float3(fs); bone.ローカル軸のZ軸の方向ベクトル = ParserHelper.get_Float3(fs); } if (bone.外部親変形である) { bone.親Key = ParserHelper.get_Int(fs); } if (bone.IKボーンである) { bone.IKターゲットボーンインデックス = ParserHelper.get_Index(fs, header.ボーンインデックスサイズ); bone.IKループ回数 = ParserHelper.get_Int(fs); bone.IK単位角rad = ParserHelper.get_Float(fs); int IKリンク数 = ParserHelper.get_Int(fs); for (int i = 0; i < IKリンク数; i++) { bone.IKリンクリスト.Add(IKリンク.読み込む(fs, header)); } } return(bone); }