4 * License : The MIT License
\r
5 * Copyright(c) 2010 MikuToga Partners
\r
8 package jp.sourceforge.mikutoga.pmd;
\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
23 * PMDモデルファイル一式に相当するもの。
\r
24 * 様々な基本構造のリストの集合から構成される。
\r
26 public class PmdModel {
\r
28 /** デフォルトのヘッダバージョン。 */
\r
29 public static final float DEF_HEADERVER = 1.0f;
\r
31 private float headerVersion = DEF_HEADERVER;
\r
33 private final I18nText modelName = new I18nText();
\r
34 private final I18nText description = new I18nText();
\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
40 private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
\r
41 private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
\r
43 private final List<IKChain> ikChainList = new ArrayList<IKChain>();
\r
45 private final Map<MorphType, List<MorphPart>> morphMap =
\r
46 new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
\r
48 private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
\r
49 private final List<RigidGroup> rigidGroupList =
\r
50 new ArrayList<RigidGroup>();
\r
52 private final List<JointInfo> jointList = new ArrayList<JointInfo>();
\r
54 private ToonMap toonMap = new ToonMap();
\r
62 assert this.vertexList instanceof RandomAccess;
\r
63 assert this.surfaceList instanceof RandomAccess;
\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
74 * PMDファイルのヘッダバージョンを返す。
\r
75 * @return PMDファイルのヘッダバージョン
\r
77 public float getHeaderVersion(){
\r
78 return this.headerVersion;
\r
82 * PMDファイルのヘッダバージョンを設定する。
\r
83 * @param ver PMDファイルのヘッダバージョン
\r
85 public void setHeaderVersion(float ver){
\r
86 this.headerVersion = ver;
\r
94 public I18nText getModelName(){
\r
95 return this.modelName;
\r
100 * 改行表現には{@literal \n}が用いられる
\r
103 public I18nText getDescription(){
\r
104 return this.description;
\r
111 public List<Vertex> getVertexList(){
\r
112 return this.vertexList;
\r
119 public List<Surface> getSurfaceList(){
\r
120 return this.surfaceList;
\r
127 public List<Material> getMaterialList(){
\r
128 return this.materialList;
\r
135 public List<BoneInfo> getBoneList(){
\r
136 return this.boneList;
\r
141 * @return ボーングループリスト
\r
143 public List<BoneGroup> getBoneGroupList(){
\r
144 return this.boneGroupList;
\r
149 * @return IKチェーンリスト
\r
151 public List<IKChain> getIKChainList(){
\r
152 return this.ikChainList;
\r
156 * 種類別モーフリストのマップを返す。
\r
157 * @return 種類別モーフリストのマップ
\r
159 public Map<MorphType, List<MorphPart>> getMorphMap(){
\r
160 return this.morphMap;
\r
167 public List<RigidInfo> getRigidList(){
\r
168 return this.rigidList;
\r
173 * @return 剛体グループリスト。
\r
175 public List<RigidGroup> getRigidGroupList(){
\r
176 return this.rigidGroupList;
\r
181 * @return 剛体間ジョイントリスト
\r
183 public List<JointInfo> getJointList(){
\r
184 return this.jointList;
\r
189 * @return トゥーンファイルマップ
\r
191 public ToonMap getToonMap(){
\r
192 return this.toonMap;
\r
196 * トゥーンファイルマップを設定する。
\r
197 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
\r
198 * @param map トゥーンファイルマップ
\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
210 * このモデルがグローバル名を含むか判定する。
\r
211 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
\r
212 * @return グローバル名を持つならtrue
\r
214 public boolean hasGlobalText(){
\r
215 if(this.modelName.hasGlobalText()) return true;
\r
216 if(this.description.hasGlobalText()) return true;
\r
218 for(BoneInfo bone : this.boneList){
\r
219 if(bone.getBoneName().hasGlobalText()) return true;
\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
231 for(BoneGroup group : this.boneGroupList){
\r
232 if(group.getGroupName().hasGlobalText()) return true;
\r
239 * モーフで使われる全てのモーフ頂点のリストを返す。
\r
240 * モーフ間で重複する頂点はマージされる。
\r
243 * 0から始まる通し番号がリナンバリングされる。
\r
244 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
\r
245 * @return モーフに使われるモーフ頂点のリスト
\r
247 public List<MorphVertex> mergeMorphVertex(){
\r
248 List<MorphVertex> result = new ArrayList<MorphVertex>();
\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
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
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
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
295 * 永続化可能な状態へトリミングする。
\r
296 * 各種オブジェクトの通し番号が変化する可能性がある。
\r
298 public void trimming(){
\r
299 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
\r
300 this.surfaceList.clear();
\r
301 this.surfaceList.addAll(trimmedSurfaceList);
\r
303 List<Vertex> trimmedVertexList = trimmingVertexList();
\r
304 this.vertexList.clear();
\r
305 this.vertexList.addAll(trimmedVertexList);
\r
312 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
\r
313 * 所属マテリアルの無い面はリストの末端に配置される。
\r
314 * 面リスト中のnullは削除され詰められる。
\r
315 * @return トリミングされた面リスト
\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
327 materialedSurfaceSet.removeAll(this.surfaceList);
\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
335 result.addAll(materialedSurfaceSet);
\r
338 for(Surface surface : result){
\r
339 surface.setSerialNumber(serialNum);
\r
349 * 所属面の無い頂点はリストの末端に配置される。
\r
350 * 頂点リスト中のnullは削除され詰められる。
\r
351 * @return トリミングされた頂点リスト
\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
362 surfacedVertexSet.removeAll(this.vertexList);
\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
370 result.addAll(surfacedVertexSet);
\r
373 for(Vertex vertex : result){
\r
374 vertex.setSerialNumber(serialNum);
\r