OSDN Git Service

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