4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sfjp.mikutoga.pmd.model;
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;
18 import java.util.RandomAccess;
20 import jp.sfjp.mikutoga.corelib.I18nText;
21 import jp.sfjp.mikutoga.pmd.MorphType;
24 * PMDモデルファイル一式に相当するもの。
25 * 様々な基本構造のリストの集合から構成される。
27 public class PmdModel {
29 private final I18nText modelName = new I18nText();
30 private final I18nText description = new I18nText();
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>();
36 private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
37 private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
39 private final List<IKChain> ikChainList = new ArrayList<IKChain>();
41 private final Map<MorphType, List<MorphPart>> morphMap =
42 new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
44 private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
45 private final List<RigidGroup> rigidGroupList =
46 new ArrayList<RigidGroup>();
48 private final List<JointInfo> jointList = new ArrayList<JointInfo>();
50 private ToonMap toonMap = new ToonMap();
59 assert this.vertexList instanceof RandomAccess;
60 assert this.surfaceList instanceof RandomAccess;
62 this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());
63 this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());
64 this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());
65 this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());
75 public I18nText getModelName(){
76 return this.modelName;
81 * 改行表現には{@literal \n}が用いられる
84 public I18nText getDescription(){
85 return this.description;
92 public List<Vertex> getVertexList(){
93 return this.vertexList;
100 public List<Surface> getSurfaceList(){
101 return this.surfaceList;
108 public List<Material> getMaterialList(){
109 return this.materialList;
116 public List<BoneInfo> getBoneList(){
117 return this.boneList;
124 public List<BoneGroup> getBoneGroupList(){
125 return this.boneGroupList;
132 public List<IKChain> getIKChainList(){
133 return this.ikChainList;
138 * @return 種類別モーフリストのマップ
140 public Map<MorphType, List<MorphPart>> getMorphMap(){
141 return this.morphMap;
148 public List<RigidInfo> getRigidList(){
149 return this.rigidList;
156 public List<RigidGroup> getRigidGroupList(){
157 return this.rigidGroupList;
162 * @return 剛体間ジョイントリスト
164 public List<JointInfo> getJointList(){
165 return this.jointList;
170 * @return トゥーンファイルマップ
172 public ToonMap getToonMap(){
178 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
179 * @param map トゥーンファイルマップ
181 public void setToonMap(ToonMap map){
183 for(Material material : this.materialList){
184 ShadeInfo info = material.getShadeInfo();
185 info.setToonMap(this.toonMap);
191 * このモデルがグローバル名を含むか判定する。
192 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
193 * @return グローバル名を持つならtrue
195 public boolean hasGlobalText(){
196 if(this.modelName.hasGlobalText()) return true;
197 if(this.description.hasGlobalText()) return true;
199 for(BoneInfo bone : this.boneList){
200 if(bone.getBoneName().hasGlobalText()) return true;
203 for(List<MorphPart> partList : this.morphMap.values()){
204 for(MorphPart part : partList){
205 if(part.getMorphName().hasGlobalText()) return true;
209 for(BoneGroup group : this.boneGroupList){
210 if(group.getGroupName().hasGlobalText()) return true;
217 * 全モーフが使う全モーフ頂点の出現順リストを返す。
218 * モーフ種別毎に固まっている事が保証される。
221 private List<MorphVertex> getAllMorphVertexList(){
222 List<MorphVertex> allList = new ArrayList<MorphVertex>();
224 for(MorphType type : this.morphMap.keySet()){
225 if(type.isBase()) continue;
227 List<MorphPart> partList = this.morphMap.get(type);
228 if(partList == null) continue;
230 for(MorphPart part : partList){
231 List<MorphVertex> morphVertexList =
232 part.getMorphVertexList();
233 allList.addAll(morphVertexList);
241 * 重複する頂点参照を除いたモーフ頂点リストを返す。
242 * @param allList モーフ頂点リスト
243 * @return 重複が除かれたモーフ頂点リスト
245 private List<MorphVertex> getUniqueMorphVertexList(
246 List<MorphVertex> allList ){
247 List<MorphVertex> result = new ArrayList<MorphVertex>();
249 Set<Vertex> mergedVertexSet = new HashSet<Vertex>();
251 for(MorphVertex morphVertex : allList){
252 Vertex vertex = morphVertex.getBaseVertex();
254 if(mergedVertexSet.contains(vertex)) continue;
256 mergedVertexSet.add(vertex);
257 result.add(morphVertex);
264 * モーフで使われる全てのモーフ頂点のリストを返す。
265 * モーフ間で重複する頂点はマージされる。
268 * 0から始まる通し番号がリナンバリングされる。
269 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
270 * @return モーフに使われるモーフ頂点のリスト
272 public List<MorphVertex> mergeMorphVertex(){
273 List<MorphVertex> result;
275 List<MorphVertex> allList = getAllMorphVertexList();
276 result = getUniqueMorphVertexList(allList);
278 Collections.sort(result, MorphVertex.VIDCOMPARATOR);
279 ListUtil.assignIndexedSerial(result);
281 Map<Vertex, MorphVertex> numberedMap =
282 new HashMap<Vertex, MorphVertex>();
283 for(MorphVertex morphVertex : result){
284 Vertex vertex = morphVertex.getBaseVertex();
285 numberedMap.put(vertex, morphVertex);
288 for(MorphVertex morphVertex : allList){
289 Vertex vertex = morphVertex.getBaseVertex();
291 MorphVertex numbered = numberedMap.get(vertex);
292 assert numbered != null;
294 int serialNo = numbered.getSerialNumber();
295 morphVertex.setSerialNumber(serialNo);
303 * 各種オブジェクトの通し番号が変化する可能性がある。
305 public void trimming(){
306 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
307 this.surfaceList.clear();
308 this.surfaceList.addAll(trimmedSurfaceList);
310 List<Vertex> trimmedVertexList = trimmingVertexList();
311 this.vertexList.clear();
312 this.vertexList.addAll(trimmedVertexList);
319 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
320 * 所属マテリアルの無い面はリストの末端に配置される。
321 * 面リスト中のnullは削除され詰められる。
322 * @return トリミングされた面リスト
324 private List<Surface> trimmingSurfaceList(){
325 Set<Surface> materialedSurfaceSet = new HashSet<Surface>();
326 for(Material material : this.materialList){
327 if(material == null) continue;
328 for(Surface surface : material){
329 if(surface == null) continue;
330 materialedSurfaceSet.add(surface);
334 materialedSurfaceSet.removeAll(this.surfaceList);
336 List<Surface> result = new ArrayList<Surface>();
337 for(Surface surface : this.surfaceList){
338 if(surface == null) continue;
342 result.addAll(materialedSurfaceSet);
345 for(Surface surface : result){
346 surface.setSerialNumber(serialNum);
356 * 所属面の無い頂点はリストの末端に配置される。
357 * 頂点リスト中のnullは削除され詰められる。
358 * @return トリミングされた頂点リスト
360 private List<Vertex> trimmingVertexList(){
361 Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();
362 for(Surface surface : this.surfaceList){
363 if(surface == null) continue;
364 for(Vertex vertex : surface){
365 surfacedVertexSet.add(vertex);
369 surfacedVertexSet.removeAll(this.vertexList);
371 List<Vertex> result = new ArrayList<Vertex>();
372 for(Vertex vertex : this.vertexList){
373 if(vertex == null) continue;
377 result.addAll(surfacedVertexSet);
380 for(Vertex vertex : result){
381 vertex.setSerialNumber(serialNum);