OSDN Git Service

use diamond operator.
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd / model / PmdModel.java
1 /*
2  * PMD model
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd.model;
9
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;
17 import java.util.Map;
18 import java.util.RandomAccess;
19 import java.util.Set;
20 import jp.sfjp.mikutoga.corelib.I18nText;
21 import jp.sfjp.mikutoga.pmd.MorphType;
22
23 /**
24  * PMDモデルファイル一式に相当するもの。
25  * 様々な基本構造のリストの集合から構成される。
26  */
27 public class PmdModel {
28
29     private final I18nText modelName = new I18nText();
30     private final I18nText description = new I18nText();
31
32     private final List<Vertex> vertexList = new ArrayList<>();
33     private final List<Surface> surfaceList = new ArrayList<>();
34     private final List<Material> materialList = new LinkedList<>();
35
36     private final List<BoneInfo> boneList = new ArrayList<>();
37     private final List<BoneGroup> boneGroupList = new ArrayList<>();
38
39     private final List<IKChain> ikChainList = new ArrayList<>();
40
41     private final Map<MorphType, List<MorphPart>> morphMap =
42             new EnumMap<>(MorphType.class);
43
44     private final List<RigidInfo> rigidList = new ArrayList<>();
45     private final List<RigidGroup> rigidGroupList =
46             new ArrayList<>();
47
48     private final List<JointInfo> jointList = new ArrayList<>();
49
50     private ToonMap toonMap = new ToonMap();
51
52
53     /**
54      * コンストラクタ。
55      */
56     public PmdModel(){
57         super();
58
59         assert this.vertexList instanceof RandomAccess;
60         assert this.surfaceList instanceof RandomAccess;
61
62         this.morphMap.put(MorphType.EYEBROW, new ArrayList<>());
63         this.morphMap.put(MorphType.EYE,     new ArrayList<>());
64         this.morphMap.put(MorphType.LIP,     new ArrayList<>());
65         this.morphMap.put(MorphType.EXTRA,   new ArrayList<>());
66
67         return;
68     }
69
70
71     /**
72      * モデル名を返す。
73      *
74      * @return モデル名
75      */
76     public I18nText getModelName(){
77         return this.modelName;
78     }
79
80     /**
81      * モデル説明文を返す。
82      * 改行表現には{@literal \n}が用いられる
83      *
84      * @return モデル説明文
85      */
86     public I18nText getDescription(){
87         return this.description;
88     }
89
90     /**
91      * 頂点リストを返す。
92      *
93      * @return 頂点リスト。
94      */
95     public List<Vertex> getVertexList(){
96         return this.vertexList;
97     }
98
99     /**
100      * 面リストを返す。
101      *
102      * @return 面リスト
103      */
104     public List<Surface> getSurfaceList(){
105         return this.surfaceList;
106     }
107
108     /**
109      * 素材リストを返す。
110      *
111      * @return 素材リスト
112      */
113     public List<Material> getMaterialList(){
114         return this.materialList;
115     }
116
117     /**
118      * ボーンリストを返す。
119      *
120      * @return ボーンリスト
121      */
122     public List<BoneInfo> getBoneList(){
123         return this.boneList;
124     }
125
126     /**
127      * ボーングループリストを返す。
128      *
129      * @return ボーングループリスト
130      */
131     public List<BoneGroup> getBoneGroupList(){
132         return this.boneGroupList;
133     }
134
135     /**
136      * IKチェーンリストを返す。
137      *
138      * @return IKチェーンリスト
139      */
140     public List<IKChain> getIKChainList(){
141         return this.ikChainList;
142     }
143
144     /**
145      * 種類別モーフリストのマップを返す。
146      *
147      * @return 種類別モーフリストのマップ
148      */
149     public Map<MorphType, List<MorphPart>> getMorphMap(){
150         return this.morphMap;
151     }
152
153     /**
154      * 剛体リストを返す。
155      *
156      * @return 剛体リスト
157      */
158     public List<RigidInfo> getRigidList(){
159         return this.rigidList;
160     }
161
162     /**
163      * 剛体グループリストを返す。
164      *
165      * @return 剛体グループリスト。
166      */
167     public List<RigidGroup> getRigidGroupList(){
168         return this.rigidGroupList;
169     }
170
171     /**
172      * 剛体間ジョイントリストを返す。
173      *
174      * @return 剛体間ジョイントリスト
175      */
176     public List<JointInfo> getJointList(){
177         return this.jointList;
178     }
179
180     /**
181      * トゥーンファイルマップを返す。
182      *
183      * @return トゥーンファイルマップ
184      */
185     public ToonMap getToonMap(){
186         return this.toonMap;
187     }
188
189     /**
190      * トゥーンファイルマップを設定する。
191      * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
192      *
193      * @param map トゥーンファイルマップ
194      */
195     public void setToonMap(ToonMap map){
196         this.toonMap = map;
197         for(Material material : this.materialList){
198             ShadeInfo info = material.getShadeInfo();
199             info.setToonMap(this.toonMap);
200         }
201         return;
202     }
203
204     /**
205      * このモデルがグローバル名を含むか判定する。
206      * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
207      *
208      * @return グローバル名を持つならtrue
209      */
210     public boolean hasGlobalText(){
211         if(this.modelName.hasGlobalText()) return true;
212         if(this.description.hasGlobalText()) return true;
213
214         for(BoneInfo bone : this.boneList){
215             if(bone.getBoneName().hasGlobalText()) return true;
216         }
217
218         for(List<MorphPart> partList : this.morphMap.values()){
219             for(MorphPart part : partList){
220                 if(part.getMorphName().hasGlobalText()) return true;
221             }
222         }
223
224         for(BoneGroup group : this.boneGroupList){
225             if(group.getGroupName().hasGlobalText()) return true;
226         }
227
228         return false;
229     }
230
231     /**
232      * 全モーフが使う全モーフ頂点の出現順リストを返す。
233      * モーフ種別毎に固まっている事が保証される。
234      *
235      * @return モーフ頂点リスト
236      */
237     private List<MorphVertex> getAllMorphVertexList(){
238         List<MorphVertex> allList = new ArrayList<>();
239
240         for(MorphType type : this.morphMap.keySet()){
241             if(type.isBase()) continue;
242
243             List<MorphPart> partList = this.morphMap.get(type);
244             if(partList == null) continue;
245
246             for(MorphPart part : partList){
247                 List<MorphVertex> morphVertexList =
248                         part.getMorphVertexList();
249                 allList.addAll(morphVertexList);
250             }
251         }
252
253         return allList;
254     }
255
256     /**
257      * 重複する頂点参照を除いたモーフ頂点リストを返す。
258      *
259      * @param allList モーフ頂点リスト
260      * @return 重複が除かれたモーフ頂点リスト
261      */
262     private List<MorphVertex> getUniqueMorphVertexList(
263             List<MorphVertex> allList ){
264         List<MorphVertex> result = new ArrayList<>();
265
266         Set<Vertex> mergedVertexSet = new HashSet<>();
267
268         for(MorphVertex morphVertex : allList){
269             Vertex vertex = morphVertex.getBaseVertex();
270
271             if(mergedVertexSet.contains(vertex)) continue;
272
273             mergedVertexSet.add(vertex);
274             result.add(morphVertex);
275         }
276
277         return result;
278     }
279
280     /**
281      * モーフで使われる全てのモーフ頂点のリストを返す。
282      * モーフ間で重複する頂点はマージされる。
283      * 頂点IDでソートされる。
284      *
285      * <p>0から始まる通し番号がリナンバリングされる。
286      * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
287      *
288      * @return モーフに使われるモーフ頂点のリスト
289      */
290     public List<MorphVertex> mergeMorphVertex(){
291         List<MorphVertex> result;
292
293         List<MorphVertex> allList = getAllMorphVertexList();
294         result = getUniqueMorphVertexList(allList);
295
296         Collections.sort(result, MorphVertex.VIDCOMPARATOR);
297         ListUtil.assignIndexedSerial(result);
298
299         Map<Vertex, MorphVertex> numberedMap =
300                 new HashMap<>();
301         for(MorphVertex morphVertex : result){
302             Vertex vertex = morphVertex.getBaseVertex();
303             numberedMap.put(vertex, morphVertex);
304         }
305
306         for(MorphVertex morphVertex : allList){
307             Vertex vertex = morphVertex.getBaseVertex();
308
309             MorphVertex numbered = numberedMap.get(vertex);
310             assert numbered != null;
311
312             int serialNo = numbered.getSerialNumber();
313             morphVertex.setSerialNumber(serialNo);
314         }
315
316         return result;
317     }
318
319     /**
320      * 永続化可能な状態へトリミングする。
321      * 各種オブジェクトの通し番号が変化する可能性がある。
322      */
323     public void trimming(){
324         List<Surface> trimmedSurfaceList = trimmingSurfaceList();
325         this.surfaceList.clear();
326         this.surfaceList.addAll(trimmedSurfaceList);
327
328         List<Vertex> trimmedVertexList = trimmingVertexList();
329         this.vertexList.clear();
330         this.vertexList.addAll(trimmedVertexList);
331
332         return;
333     }
334
335     /**
336      * 面リストをトリミングする。
337      * 所属マテリアル順に再配置し、通し番号を割り振り直す。
338      * 所属マテリアルの無い面はリストの末端に配置される。
339      * 面リスト中のnullは削除され詰められる。
340      *
341      * @return トリミングされた面リスト
342      */
343     private List<Surface> trimmingSurfaceList(){
344         Set<Surface> materialedSurfaceSet = new HashSet<>();
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);
350             }
351         }
352
353         materialedSurfaceSet.removeAll(this.surfaceList);
354
355         List<Surface> result = new ArrayList<>();
356         for(Surface surface : this.surfaceList){
357             if(surface == null) continue;
358             result.add(surface);
359         }
360
361         result.addAll(materialedSurfaceSet);
362
363         int serialNum = 0;
364         for(Surface surface : result){
365             surface.setSerialNumber(serialNum);
366             serialNum++;
367         }
368
369         return result;
370     }
371
372     /**
373      * 頂点リストをトリミングする。
374      * 通し番号を振り直す。
375      * 所属面の無い頂点はリストの末端に配置される。
376      * 頂点リスト中のnullは削除され詰められる。
377      *
378      * @return トリミングされた頂点リスト
379      */
380     private List<Vertex> trimmingVertexList(){
381         Set<Vertex> surfacedVertexSet = new HashSet<>();
382         for(Surface surface : this.surfaceList){
383             if(surface == null) continue;
384             for(Vertex vertex : surface){
385                 surfacedVertexSet.add(vertex);
386             }
387         }
388
389         surfacedVertexSet.removeAll(this.vertexList);
390
391         List<Vertex> result = new ArrayList<>();
392         for(Vertex vertex : this.vertexList){
393             if(vertex == null) continue;
394             result.add(vertex);
395         }
396
397         result.addAll(surfacedVertexSet);
398
399         int serialNum = 0;
400         for(Vertex vertex : result){
401             vertex.setSerialNumber(serialNum);
402             serialNum++;
403         }
404
405         return result;
406     }
407
408 }