-/*\r
- * PMD model\r
- *\r
- * License : The MIT License\r
- * Copyright(c) 2010 MikuToga Partners\r
- */\r
-\r
-package jp.sourceforge.mikutoga.pmd;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.EnumMap;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.RandomAccess;\r
-import java.util.Set;\r
-import jp.sourceforge.mikutoga.corelib.I18nText;\r
-\r
-/**\r
- * PMDモデルファイル一式に相当するもの。\r
- * 様々な基本構造のリストの集合から構成される。\r
- */\r
-public class PmdModel {\r
-\r
- /** デフォルトのヘッダバージョン。 */\r
- public static final float DEF_HEADERVER = 1.0f;\r
-\r
- private float headerVersion = DEF_HEADERVER;\r
-\r
- private final I18nText modelName = new I18nText();\r
- private final I18nText description = new I18nText();\r
-\r
- private final List<Vertex> vertexList = new ArrayList<Vertex>();\r
- private final List<Surface> surfaceList = new ArrayList<Surface>();\r
- private final List<Material> materialList = new LinkedList<Material>();\r
-\r
- private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();\r
- private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();\r
-\r
- private final List<IKChain> ikChainList = new ArrayList<IKChain>();\r
-\r
- private final Map<MorphType, List<MorphPart>> morphMap =\r
- new EnumMap<MorphType, List<MorphPart>>(MorphType.class);\r
-\r
- private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();\r
- private final List<RigidGroup> rigidGroupList =\r
- new ArrayList<RigidGroup>();\r
-\r
- private final List<JointInfo> jointList = new ArrayList<JointInfo>();\r
-\r
- private ToonMap toonMap = new ToonMap();\r
-\r
- /**\r
- * コンストラクタ。\r
- */\r
- public PmdModel(){\r
- super();\r
-\r
- assert this.vertexList instanceof RandomAccess;\r
- assert this.surfaceList instanceof RandomAccess;\r
-\r
- this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());\r
- this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());\r
- this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());\r
- this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * PMDファイルのヘッダバージョンを返す。\r
- * @return PMDファイルのヘッダバージョン\r
- */\r
- public float getHeaderVersion(){\r
- return this.headerVersion;\r
- }\r
-\r
- /**\r
- * PMDファイルのヘッダバージョンを設定する。\r
- * @param ver PMDファイルのヘッダバージョン\r
- */\r
- public void setHeaderVersion(float ver){\r
- this.headerVersion = ver;\r
- return;\r
- }\r
-\r
- /**\r
- * モデル名を返す。\r
- * @return モデル名\r
- */\r
- public I18nText getModelName(){\r
- return this.modelName;\r
- }\r
-\r
- /**\r
- * モデル説明文を返す。\r
- * 改行表現には{@literal \n}が用いられる\r
- * @return モデル説明文\r
- */\r
- public I18nText getDescription(){\r
- return this.description;\r
- }\r
-\r
- /**\r
- * 頂点リストを返す。\r
- * @return 頂点リスト。\r
- */\r
- public List<Vertex> getVertexList(){\r
- return this.vertexList;\r
- }\r
-\r
- /**\r
- * 面リストを返す。\r
- * @return 面リスト\r
- */\r
- public List<Surface> getSurfaceList(){\r
- return this.surfaceList;\r
- }\r
-\r
- /**\r
- * 素材リストを返す。\r
- * @return 素材リスト\r
- */\r
- public List<Material> getMaterialList(){\r
- return this.materialList;\r
- }\r
-\r
- /**\r
- * ボーンリストを返す。\r
- * @return ボーンリスト\r
- */\r
- public List<BoneInfo> getBoneList(){\r
- return this.boneList;\r
- }\r
-\r
- /**\r
- * ボーングループリストを返す。\r
- * @return ボーングループリスト\r
- */\r
- public List<BoneGroup> getBoneGroupList(){\r
- return this.boneGroupList;\r
- }\r
-\r
- /**\r
- * IKチェーンリストを返す。\r
- * @return IKチェーンリスト\r
- */\r
- public List<IKChain> getIKChainList(){\r
- return this.ikChainList;\r
- }\r
-\r
- /**\r
- * 種類別モーフリストのマップを返す。\r
- * @return 種類別モーフリストのマップ\r
- */\r
- public Map<MorphType, List<MorphPart>> getMorphMap(){\r
- return this.morphMap;\r
- }\r
-\r
- /**\r
- * 剛体リストを返す。\r
- * @return 剛体リスト\r
- */\r
- public List<RigidInfo> getRigidList(){\r
- return this.rigidList;\r
- }\r
-\r
- /**\r
- * 剛体グループリストを返す。\r
- * @return 剛体グループリスト。\r
- */\r
- public List<RigidGroup> getRigidGroupList(){\r
- return this.rigidGroupList;\r
- }\r
-\r
- /**\r
- * 剛体間ジョイントリストを返す。\r
- * @return 剛体間ジョイントリスト\r
- */\r
- public List<JointInfo> getJointList(){\r
- return this.jointList;\r
- }\r
-\r
- /**\r
- * トゥーンファイルマップを返す。\r
- * @return トゥーンファイルマップ\r
- */\r
- public ToonMap getToonMap(){\r
- return this.toonMap;\r
- }\r
-\r
- /**\r
- * トゥーンファイルマップを設定する。\r
- * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。\r
- * @param map トゥーンファイルマップ\r
- */\r
- public void setToonMap(ToonMap map){\r
- this.toonMap = map;\r
- for(Material material : this.materialList){\r
- ShadeInfo info = material.getShadeInfo();\r
- info.setToonMap(this.toonMap);\r
- }\r
- return;\r
- }\r
-\r
- /**\r
- * このモデルがグローバル名を含むか判定する。\r
- * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。\r
- * @return グローバル名を持つならtrue\r
- */\r
- public boolean hasGlobalText(){\r
- if(this.modelName.hasGlobalText()) return true;\r
- if(this.description.hasGlobalText()) return true;\r
-\r
- for(BoneInfo bone : this.boneList){\r
- if(bone.getBoneName().hasGlobalText()) return true;\r
- }\r
-\r
- List<MorphType> typeList = new ArrayList<MorphType>();\r
- typeList.addAll(this.morphMap.keySet());\r
- for(MorphType type : typeList){\r
- List<MorphPart> partList = this.morphMap.get(type);\r
- for(MorphPart part : partList){\r
- if(part.getMorphName().hasGlobalText()) return true;\r
- }\r
- }\r
-\r
- for(BoneGroup group : this.boneGroupList){\r
- if(group.getGroupName().hasGlobalText()) return true;\r
- }\r
-\r
- return false;\r
- }\r
-\r
- /**\r
- * モーフで使われる全てのモーフ頂点のリストを返す。\r
- * モーフ間で重複する頂点はマージされる。\r
- * 頂点IDでソートされる。\r
- * <p>\r
- * 0から始まる通し番号がリナンバリングされる。\r
- * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。\r
- * @return モーフに使われるモーフ頂点のリスト\r
- */\r
- public List<MorphVertex> mergeMorphVertex(){\r
- List<MorphVertex> result = new ArrayList<MorphVertex>();\r
-\r
- Set<Vertex> mergedVertexSet = new HashSet<Vertex>();\r
- for(MorphType type : this.morphMap.keySet()){\r
- if(type.isBase()) continue;\r
- List<MorphPart> partList = this.morphMap.get(type);\r
- if(partList == null) continue;\r
- for(MorphPart part : partList){\r
- for(MorphVertex morphVertex : part){\r
- Vertex vertex = morphVertex.getBaseVertex();\r
- if(mergedVertexSet.contains(vertex)) continue;\r
- mergedVertexSet.add(vertex);\r
- result.add(morphVertex);\r
- }\r
- }\r
- }\r
-\r
- Collections.sort(result, MorphVertex.VIDCOMPARATOR);\r
- for(int idx = 0; idx < result.size(); idx++){\r
- MorphVertex morphVertex = result.get(idx);\r
- morphVertex.setSerialNumber(idx);\r
- }\r
-\r
- Map<Vertex, MorphVertex> numberedMap =\r
- new HashMap<Vertex, MorphVertex>();\r
- for(MorphVertex morphVertex : result){\r
- numberedMap.put(morphVertex.getBaseVertex(), morphVertex);\r
- }\r
-\r
- for(MorphType type : this.morphMap.keySet()){\r
- if(type.isBase()) continue;\r
- List<MorphPart> partList = this.morphMap.get(type);\r
- if(partList == null) continue;\r
- for(MorphPart part : partList){\r
- for(MorphVertex morphVertex : part){\r
- Vertex vertex = morphVertex.getBaseVertex();\r
- MorphVertex numbered = numberedMap.get(vertex);\r
- assert numbered != null;\r
- morphVertex.setSerialNumber(numbered.getSerialNumber());\r
- }\r
- }\r
- }\r
-\r
- return result;\r
- }\r
-\r
- /**\r
- * 永続化可能な状態へトリミングする。\r
- * 各種オブジェクトの通し番号が変化する可能性がある。\r
- */\r
- public void trimming(){\r
- List<Surface> trimmedSurfaceList = trimmingSurfaceList();\r
- this.surfaceList.clear();\r
- this.surfaceList.addAll(trimmedSurfaceList);\r
-\r
- List<Vertex> trimmedVertexList = trimmingVertexList();\r
- this.vertexList.clear();\r
- this.vertexList.addAll(trimmedVertexList);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * 面リストをトリミングする。\r
- * 所属マテリアル順に再配置し、通し番号を割り振り直す。\r
- * 所属マテリアルの無い面はリストの末端に配置される。\r
- * 面リスト中のnullは削除され詰められる。\r
- * @return トリミングされた面リスト\r
- */\r
- private List<Surface> trimmingSurfaceList(){\r
- Set<Surface> materialedSurfaceSet = new HashSet<Surface>();\r
- for(Material material : this.materialList){\r
- if(material == null) continue;\r
- for(Surface surface : material){\r
- if(surface == null) continue;\r
- materialedSurfaceSet.add(surface);\r
- }\r
- }\r
-\r
- materialedSurfaceSet.removeAll(this.surfaceList);\r
-\r
- List<Surface> result = new ArrayList<Surface>();\r
- for(Surface surface : this.surfaceList){\r
- if(surface == null) continue;\r
- result.add(surface);\r
- }\r
-\r
- result.addAll(materialedSurfaceSet);\r
-\r
- int serialNum = 0;\r
- for(Surface surface : result){\r
- surface.setSerialNumber(serialNum);\r
- serialNum++;\r
- }\r
-\r
- return result;\r
- }\r
-\r
- /**\r
- * 頂点リストをトリミングする。\r
- * 通し番号を振り直す。\r
- * 所属面の無い頂点はリストの末端に配置される。\r
- * 頂点リスト中のnullは削除され詰められる。\r
- * @return トリミングされた頂点リスト\r
- */\r
- private List<Vertex> trimmingVertexList(){\r
- Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();\r
- for(Surface surface : this.surfaceList){\r
- if(surface == null) continue;\r
- for(Vertex vertex : surface){\r
- surfacedVertexSet.add(vertex);\r
- }\r
- }\r
-\r
- surfacedVertexSet.removeAll(this.vertexList);\r
-\r
- List<Vertex> result = new ArrayList<Vertex>();\r
- for(Vertex vertex : this.vertexList){\r
- if(vertex == null) continue;\r
- result.add(vertex);\r
- }\r
-\r
- result.addAll(surfacedVertexSet);\r
-\r
- int serialNum = 0;\r
- for(Vertex vertex : result){\r
- vertex.setSerialNumber(serialNum);\r
- serialNum++;\r
- }\r
-\r
- return result;\r
- }\r
-\r
-}\r
+/*
+ * PMD model
+ *
+ * License : The MIT License
+ * Copyright(c) 2010 MikuToga Partners
+ */
+
+package jp.sourceforge.mikutoga.pmd;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.RandomAccess;
+import java.util.Set;
+import jp.sourceforge.mikutoga.corelib.I18nText;
+
+/**
+ * PMDモデルファイル一式に相当するもの。
+ * 様々な基本構造のリストの集合から構成される。
+ */
+public class PmdModel {
+
+ /** デフォルトのヘッダバージョン。 */
+ public static final float DEF_HEADERVER = 1.0f;
+
+ private float headerVersion = DEF_HEADERVER;
+
+ private final I18nText modelName = new I18nText();
+ private final I18nText description = new I18nText();
+
+ private final List<Vertex> vertexList = new ArrayList<Vertex>();
+ private final List<Surface> surfaceList = new ArrayList<Surface>();
+ private final List<Material> materialList = new LinkedList<Material>();
+
+ private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
+ private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
+
+ private final List<IKChain> ikChainList = new ArrayList<IKChain>();
+
+ private final Map<MorphType, List<MorphPart>> morphMap =
+ new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
+
+ private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
+ private final List<RigidGroup> rigidGroupList =
+ new ArrayList<RigidGroup>();
+
+ private final List<JointInfo> jointList = new ArrayList<JointInfo>();
+
+ private ToonMap toonMap = new ToonMap();
+
+ /**
+ * コンストラクタ。
+ */
+ public PmdModel(){
+ super();
+
+ assert this.vertexList instanceof RandomAccess;
+ assert this.surfaceList instanceof RandomAccess;
+
+ this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());
+ this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());
+ this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());
+ this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());
+
+ return;
+ }
+
+ /**
+ * PMDファイルのヘッダバージョンを返す。
+ * @return PMDファイルのヘッダバージョン
+ */
+ public float getHeaderVersion(){
+ return this.headerVersion;
+ }
+
+ /**
+ * PMDファイルのヘッダバージョンを設定する。
+ * @param ver PMDファイルのヘッダバージョン
+ */
+ public void setHeaderVersion(float ver){
+ this.headerVersion = ver;
+ return;
+ }
+
+ /**
+ * モデル名を返す。
+ * @return モデル名
+ */
+ public I18nText getModelName(){
+ return this.modelName;
+ }
+
+ /**
+ * モデル説明文を返す。
+ * 改行表現には{@literal \n}が用いられる
+ * @return モデル説明文
+ */
+ public I18nText getDescription(){
+ return this.description;
+ }
+
+ /**
+ * 頂点リストを返す。
+ * @return 頂点リスト。
+ */
+ public List<Vertex> getVertexList(){
+ return this.vertexList;
+ }
+
+ /**
+ * 面リストを返す。
+ * @return 面リスト
+ */
+ public List<Surface> getSurfaceList(){
+ return this.surfaceList;
+ }
+
+ /**
+ * 素材リストを返す。
+ * @return 素材リスト
+ */
+ public List<Material> getMaterialList(){
+ return this.materialList;
+ }
+
+ /**
+ * ボーンリストを返す。
+ * @return ボーンリスト
+ */
+ public List<BoneInfo> getBoneList(){
+ return this.boneList;
+ }
+
+ /**
+ * ボーングループリストを返す。
+ * @return ボーングループリスト
+ */
+ public List<BoneGroup> getBoneGroupList(){
+ return this.boneGroupList;
+ }
+
+ /**
+ * IKチェーンリストを返す。
+ * @return IKチェーンリスト
+ */
+ public List<IKChain> getIKChainList(){
+ return this.ikChainList;
+ }
+
+ /**
+ * 種類別モーフリストのマップを返す。
+ * @return 種類別モーフリストのマップ
+ */
+ public Map<MorphType, List<MorphPart>> getMorphMap(){
+ return this.morphMap;
+ }
+
+ /**
+ * 剛体リストを返す。
+ * @return 剛体リスト
+ */
+ public List<RigidInfo> getRigidList(){
+ return this.rigidList;
+ }
+
+ /**
+ * 剛体グループリストを返す。
+ * @return 剛体グループリスト。
+ */
+ public List<RigidGroup> getRigidGroupList(){
+ return this.rigidGroupList;
+ }
+
+ /**
+ * 剛体間ジョイントリストを返す。
+ * @return 剛体間ジョイントリスト
+ */
+ public List<JointInfo> getJointList(){
+ return this.jointList;
+ }
+
+ /**
+ * トゥーンファイルマップを返す。
+ * @return トゥーンファイルマップ
+ */
+ public ToonMap getToonMap(){
+ return this.toonMap;
+ }
+
+ /**
+ * トゥーンファイルマップを設定する。
+ * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
+ * @param map トゥーンファイルマップ
+ */
+ public void setToonMap(ToonMap map){
+ this.toonMap = map;
+ for(Material material : this.materialList){
+ ShadeInfo info = material.getShadeInfo();
+ info.setToonMap(this.toonMap);
+ }
+ return;
+ }
+
+ /**
+ * このモデルがグローバル名を含むか判定する。
+ * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
+ * @return グローバル名を持つならtrue
+ */
+ public boolean hasGlobalText(){
+ if(this.modelName.hasGlobalText()) return true;
+ if(this.description.hasGlobalText()) return true;
+
+ for(BoneInfo bone : this.boneList){
+ if(bone.getBoneName().hasGlobalText()) return true;
+ }
+
+ List<MorphType> typeList = new ArrayList<MorphType>();
+ typeList.addAll(this.morphMap.keySet());
+ for(MorphType type : typeList){
+ List<MorphPart> partList = this.morphMap.get(type);
+ for(MorphPart part : partList){
+ if(part.getMorphName().hasGlobalText()) return true;
+ }
+ }
+
+ for(BoneGroup group : this.boneGroupList){
+ if(group.getGroupName().hasGlobalText()) return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * モーフで使われる全てのモーフ頂点のリストを返す。
+ * モーフ間で重複する頂点はマージされる。
+ * 頂点IDでソートされる。
+ * <p>
+ * 0から始まる通し番号がリナンバリングされる。
+ * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
+ * @return モーフに使われるモーフ頂点のリスト
+ */
+ public List<MorphVertex> mergeMorphVertex(){
+ List<MorphVertex> result = new ArrayList<MorphVertex>();
+
+ Set<Vertex> mergedVertexSet = new HashSet<Vertex>();
+ for(MorphType type : this.morphMap.keySet()){
+ if(type.isBase()) continue;
+ List<MorphPart> partList = this.morphMap.get(type);
+ if(partList == null) continue;
+ for(MorphPart part : partList){
+ for(MorphVertex morphVertex : part){
+ Vertex vertex = morphVertex.getBaseVertex();
+ if(mergedVertexSet.contains(vertex)) continue;
+ mergedVertexSet.add(vertex);
+ result.add(morphVertex);
+ }
+ }
+ }
+
+ Collections.sort(result, MorphVertex.VIDCOMPARATOR);
+ for(int idx = 0; idx < result.size(); idx++){
+ MorphVertex morphVertex = result.get(idx);
+ morphVertex.setSerialNumber(idx);
+ }
+
+ Map<Vertex, MorphVertex> numberedMap =
+ new HashMap<Vertex, MorphVertex>();
+ for(MorphVertex morphVertex : result){
+ numberedMap.put(morphVertex.getBaseVertex(), morphVertex);
+ }
+
+ for(MorphType type : this.morphMap.keySet()){
+ if(type.isBase()) continue;
+ List<MorphPart> partList = this.morphMap.get(type);
+ if(partList == null) continue;
+ for(MorphPart part : partList){
+ for(MorphVertex morphVertex : part){
+ Vertex vertex = morphVertex.getBaseVertex();
+ MorphVertex numbered = numberedMap.get(vertex);
+ assert numbered != null;
+ morphVertex.setSerialNumber(numbered.getSerialNumber());
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * 永続化可能な状態へトリミングする。
+ * 各種オブジェクトの通し番号が変化する可能性がある。
+ */
+ public void trimming(){
+ List<Surface> trimmedSurfaceList = trimmingSurfaceList();
+ this.surfaceList.clear();
+ this.surfaceList.addAll(trimmedSurfaceList);
+
+ List<Vertex> trimmedVertexList = trimmingVertexList();
+ this.vertexList.clear();
+ this.vertexList.addAll(trimmedVertexList);
+
+ return;
+ }
+
+ /**
+ * 面リストをトリミングする。
+ * 所属マテリアル順に再配置し、通し番号を割り振り直す。
+ * 所属マテリアルの無い面はリストの末端に配置される。
+ * 面リスト中のnullは削除され詰められる。
+ * @return トリミングされた面リスト
+ */
+ private List<Surface> trimmingSurfaceList(){
+ Set<Surface> materialedSurfaceSet = new HashSet<Surface>();
+ for(Material material : this.materialList){
+ if(material == null) continue;
+ for(Surface surface : material){
+ if(surface == null) continue;
+ materialedSurfaceSet.add(surface);
+ }
+ }
+
+ materialedSurfaceSet.removeAll(this.surfaceList);
+
+ List<Surface> result = new ArrayList<Surface>();
+ for(Surface surface : this.surfaceList){
+ if(surface == null) continue;
+ result.add(surface);
+ }
+
+ result.addAll(materialedSurfaceSet);
+
+ int serialNum = 0;
+ for(Surface surface : result){
+ surface.setSerialNumber(serialNum);
+ serialNum++;
+ }
+
+ return result;
+ }
+
+ /**
+ * 頂点リストをトリミングする。
+ * 通し番号を振り直す。
+ * 所属面の無い頂点はリストの末端に配置される。
+ * 頂点リスト中のnullは削除され詰められる。
+ * @return トリミングされた頂点リスト
+ */
+ private List<Vertex> trimmingVertexList(){
+ Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();
+ for(Surface surface : this.surfaceList){
+ if(surface == null) continue;
+ for(Vertex vertex : surface){
+ surfacedVertexSet.add(vertex);
+ }
+ }
+
+ surfacedVertexSet.removeAll(this.vertexList);
+
+ List<Vertex> result = new ArrayList<Vertex>();
+ for(Vertex vertex : this.vertexList){
+ if(vertex == null) continue;
+ result.add(vertex);
+ }
+
+ result.addAll(surfacedVertexSet);
+
+ int serialNum = 0;
+ for(Vertex vertex : result){
+ vertex.setSerialNumber(serialNum);
+ serialNum++;
+ }
+
+ return result;
+ }
+
+}