OSDN Git Service

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