OSDN Git Service

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