4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sfjp.mikutoga.pmd.model;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.EnumMap;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.LinkedList;
16 import java.util.List;
18 import java.util.RandomAccess;
20 import jp.sfjp.mikutoga.corelib.I18nText;
21 import jp.sfjp.mikutoga.pmd.MorphType;
24 * PMDモデルファイル一式に相当するもの。
25 * 様々な基本構造のリストの集合から構成される。
27 public class PmdModel {
29 private final I18nText modelName = new I18nText();
30 private final I18nText description = new I18nText();
32 private final List<Vertex> vertexList = new ArrayList<Vertex>();
33 private final List<Surface> surfaceList = new ArrayList<Surface>();
34 private final List<Material> materialList = new LinkedList<Material>();
36 private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
37 private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
39 private final List<IKChain> ikChainList = new ArrayList<IKChain>();
41 private final Map<MorphType, List<MorphPart>> morphMap =
42 new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
44 private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
45 private final List<RigidGroup> rigidGroupList =
46 new ArrayList<RigidGroup>();
48 private final List<JointInfo> jointList = new ArrayList<JointInfo>();
50 private ToonMap toonMap = new ToonMap();
59 assert this.vertexList instanceof RandomAccess;
60 assert this.surfaceList instanceof RandomAccess;
62 this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());
63 this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());
64 this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());
65 this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());
76 public I18nText getModelName(){
77 return this.modelName;
82 * 改行表現には{@literal \n}が用いられる
86 public I18nText getDescription(){
87 return this.description;
95 public List<Vertex> getVertexList(){
96 return this.vertexList;
104 public List<Surface> getSurfaceList(){
105 return this.surfaceList;
113 public List<Material> getMaterialList(){
114 return this.materialList;
122 public List<BoneInfo> getBoneList(){
123 return this.boneList;
131 public List<BoneGroup> getBoneGroupList(){
132 return this.boneGroupList;
140 public List<IKChain> getIKChainList(){
141 return this.ikChainList;
147 * @return 種類別モーフリストのマップ
149 public Map<MorphType, List<MorphPart>> getMorphMap(){
150 return this.morphMap;
158 public List<RigidInfo> getRigidList(){
159 return this.rigidList;
167 public List<RigidGroup> getRigidGroupList(){
168 return this.rigidGroupList;
174 * @return 剛体間ジョイントリスト
176 public List<JointInfo> getJointList(){
177 return this.jointList;
183 * @return トゥーンファイルマップ
185 public ToonMap getToonMap(){
191 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
193 * @param map トゥーンファイルマップ
195 public void setToonMap(ToonMap map){
197 for(Material material : this.materialList){
198 ShadeInfo info = material.getShadeInfo();
199 info.setToonMap(this.toonMap);
205 * このモデルがグローバル名を含むか判定する。
206 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
208 * @return グローバル名を持つならtrue
210 public boolean hasGlobalText(){
211 if(this.modelName.hasGlobalText()) return true;
212 if(this.description.hasGlobalText()) return true;
214 for(BoneInfo bone : this.boneList){
215 if(bone.getBoneName().hasGlobalText()) return true;
218 for(List<MorphPart> partList : this.morphMap.values()){
219 for(MorphPart part : partList){
220 if(part.getMorphName().hasGlobalText()) return true;
224 for(BoneGroup group : this.boneGroupList){
225 if(group.getGroupName().hasGlobalText()) return true;
232 * 全モーフが使う全モーフ頂点の出現順リストを返す。
233 * モーフ種別毎に固まっている事が保証される。
237 private List<MorphVertex> getAllMorphVertexList(){
238 List<MorphVertex> allList = new ArrayList<MorphVertex>();
240 for(MorphType type : this.morphMap.keySet()){
241 if(type.isBase()) continue;
243 List<MorphPart> partList = this.morphMap.get(type);
244 if(partList == null) continue;
246 for(MorphPart part : partList){
247 List<MorphVertex> morphVertexList =
248 part.getMorphVertexList();
249 allList.addAll(morphVertexList);
257 * 重複する頂点参照を除いたモーフ頂点リストを返す。
259 * @param allList モーフ頂点リスト
260 * @return 重複が除かれたモーフ頂点リスト
262 private List<MorphVertex> getUniqueMorphVertexList(
263 List<MorphVertex> allList ){
264 List<MorphVertex> result = new ArrayList<MorphVertex>();
266 Set<Vertex> mergedVertexSet = new HashSet<Vertex>();
268 for(MorphVertex morphVertex : allList){
269 Vertex vertex = morphVertex.getBaseVertex();
271 if(mergedVertexSet.contains(vertex)) continue;
273 mergedVertexSet.add(vertex);
274 result.add(morphVertex);
281 * モーフで使われる全てのモーフ頂点のリストを返す。
282 * モーフ間で重複する頂点はマージされる。
285 * <p>0から始まる通し番号がリナンバリングされる。
286 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
288 * @return モーフに使われるモーフ頂点のリスト
290 public List<MorphVertex> mergeMorphVertex(){
291 List<MorphVertex> result;
293 List<MorphVertex> allList = getAllMorphVertexList();
294 result = getUniqueMorphVertexList(allList);
296 Collections.sort(result, MorphVertex.VIDCOMPARATOR);
297 ListUtil.assignIndexedSerial(result);
299 Map<Vertex, MorphVertex> numberedMap =
300 new HashMap<Vertex, MorphVertex>();
301 for(MorphVertex morphVertex : result){
302 Vertex vertex = morphVertex.getBaseVertex();
303 numberedMap.put(vertex, morphVertex);
306 for(MorphVertex morphVertex : allList){
307 Vertex vertex = morphVertex.getBaseVertex();
309 MorphVertex numbered = numberedMap.get(vertex);
310 assert numbered != null;
312 int serialNo = numbered.getSerialNumber();
313 morphVertex.setSerialNumber(serialNo);
321 * 各種オブジェクトの通し番号が変化する可能性がある。
323 public void trimming(){
324 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
325 this.surfaceList.clear();
326 this.surfaceList.addAll(trimmedSurfaceList);
328 List<Vertex> trimmedVertexList = trimmingVertexList();
329 this.vertexList.clear();
330 this.vertexList.addAll(trimmedVertexList);
337 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
338 * 所属マテリアルの無い面はリストの末端に配置される。
339 * 面リスト中のnullは削除され詰められる。
341 * @return トリミングされた面リスト
343 private List<Surface> trimmingSurfaceList(){
344 Set<Surface> materialedSurfaceSet = new HashSet<Surface>();
345 for(Material material : this.materialList){
346 if(material == null) continue;
347 for(Surface surface : material){
348 if(surface == null) continue;
349 materialedSurfaceSet.add(surface);
353 materialedSurfaceSet.removeAll(this.surfaceList);
355 List<Surface> result = new ArrayList<Surface>();
356 for(Surface surface : this.surfaceList){
357 if(surface == null) continue;
361 result.addAll(materialedSurfaceSet);
364 for(Surface surface : result){
365 surface.setSerialNumber(serialNum);
375 * 所属面の無い頂点はリストの末端に配置される。
376 * 頂点リスト中のnullは削除され詰められる。
378 * @return トリミングされた頂点リスト
380 private List<Vertex> trimmingVertexList(){
381 Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();
382 for(Surface surface : this.surfaceList){
383 if(surface == null) continue;
384 for(Vertex vertex : surface){
385 surfacedVertexSet.add(vertex);
389 surfacedVertexSet.removeAll(this.vertexList);
391 List<Vertex> result = new ArrayList<Vertex>();
392 for(Vertex vertex : this.vertexList){
393 if(vertex == null) continue;
397 result.addAll(surfacedVertexSet);
400 for(Vertex vertex : result){
401 vertex.setSerialNumber(serialNum);