OSDN Git Service

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