4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sourceforge.mikutoga.pmd;
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.sourceforge.mikutoga.corelib.I18nText;
23 * PMDモデルファイル一式に相当するもの。
24 * 様々な基本構造のリストの集合から構成される。
26 public class PmdModel {
28 /** デフォルトのヘッダバージョン。 */
29 public static final float DEF_HEADERVER = 1.0f;
31 private float headerVersion = DEF_HEADERVER;
33 private final I18nText modelName = new I18nText();
34 private final I18nText description = new I18nText();
36 private final List<Vertex> vertexList = new ArrayList<Vertex>();
37 private final List<Surface> surfaceList = new ArrayList<Surface>();
38 private final List<Material> materialList = new LinkedList<Material>();
40 private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
41 private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
43 private final List<IKChain> ikChainList = new ArrayList<IKChain>();
45 private final Map<MorphType, List<MorphPart>> morphMap =
46 new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
48 private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
49 private final List<RigidGroup> rigidGroupList =
50 new ArrayList<RigidGroup>();
52 private final List<JointInfo> jointList = new ArrayList<JointInfo>();
54 private ToonMap toonMap = new ToonMap();
62 assert this.vertexList instanceof RandomAccess;
63 assert this.surfaceList instanceof RandomAccess;
65 this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());
66 this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());
67 this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());
68 this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());
74 * PMDファイルのヘッダバージョンを返す。
75 * @return PMDファイルのヘッダバージョン
77 public float getHeaderVersion(){
78 return this.headerVersion;
82 * PMDファイルのヘッダバージョンを設定する。
83 * @param ver PMDファイルのヘッダバージョン
85 public void setHeaderVersion(float ver){
86 this.headerVersion = ver;
94 public I18nText getModelName(){
95 return this.modelName;
100 * 改行表現には{@literal \n}が用いられる
103 public I18nText getDescription(){
104 return this.description;
111 public List<Vertex> getVertexList(){
112 return this.vertexList;
119 public List<Surface> getSurfaceList(){
120 return this.surfaceList;
127 public List<Material> getMaterialList(){
128 return this.materialList;
135 public List<BoneInfo> getBoneList(){
136 return this.boneList;
143 public List<BoneGroup> getBoneGroupList(){
144 return this.boneGroupList;
151 public List<IKChain> getIKChainList(){
152 return this.ikChainList;
157 * @return 種類別モーフリストのマップ
159 public Map<MorphType, List<MorphPart>> getMorphMap(){
160 return this.morphMap;
167 public List<RigidInfo> getRigidList(){
168 return this.rigidList;
175 public List<RigidGroup> getRigidGroupList(){
176 return this.rigidGroupList;
181 * @return 剛体間ジョイントリスト
183 public List<JointInfo> getJointList(){
184 return this.jointList;
189 * @return トゥーンファイルマップ
191 public ToonMap getToonMap(){
197 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
198 * @param map トゥーンファイルマップ
200 public void setToonMap(ToonMap map){
202 for(Material material : this.materialList){
203 ShadeInfo info = material.getShadeInfo();
204 info.setToonMap(this.toonMap);
210 * このモデルがグローバル名を含むか判定する。
211 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
212 * @return グローバル名を持つならtrue
214 public boolean hasGlobalText(){
215 if(this.modelName.hasGlobalText()) return true;
216 if(this.description.hasGlobalText()) return true;
218 for(BoneInfo bone : this.boneList){
219 if(bone.getBoneName().hasGlobalText()) return true;
222 List<MorphType> typeList = new ArrayList<MorphType>();
223 typeList.addAll(this.morphMap.keySet());
224 for(MorphType type : typeList){
225 List<MorphPart> partList = this.morphMap.get(type);
226 for(MorphPart part : partList){
227 if(part.getMorphName().hasGlobalText()) return true;
231 for(BoneGroup group : this.boneGroupList){
232 if(group.getGroupName().hasGlobalText()) return true;
239 * モーフで使われる全てのモーフ頂点のリストを返す。
240 * モーフ間で重複する頂点はマージされる。
243 * 0から始まる通し番号がリナンバリングされる。
244 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
245 * @return モーフに使われるモーフ頂点のリスト
247 public List<MorphVertex> mergeMorphVertex(){
248 List<MorphVertex> result = new ArrayList<MorphVertex>();
250 Set<Vertex> mergedVertexSet = new HashSet<Vertex>();
251 for(MorphType type : this.morphMap.keySet()){
252 if(type.isBase()) continue;
253 List<MorphPart> partList = this.morphMap.get(type);
254 if(partList == null) continue;
255 for(MorphPart part : partList){
256 for(MorphVertex morphVertex : part){
257 Vertex vertex = morphVertex.getBaseVertex();
258 if(mergedVertexSet.contains(vertex)) continue;
259 mergedVertexSet.add(vertex);
260 result.add(morphVertex);
265 Collections.sort(result, MorphVertex.VIDCOMPARATOR);
266 for(int idx = 0; idx < result.size(); idx++){
267 MorphVertex morphVertex = result.get(idx);
268 morphVertex.setSerialNumber(idx);
271 Map<Vertex, MorphVertex> numberedMap =
272 new HashMap<Vertex, MorphVertex>();
273 for(MorphVertex morphVertex : result){
274 numberedMap.put(morphVertex.getBaseVertex(), morphVertex);
277 for(MorphType type : this.morphMap.keySet()){
278 if(type.isBase()) continue;
279 List<MorphPart> partList = this.morphMap.get(type);
280 if(partList == null) continue;
281 for(MorphPart part : partList){
282 for(MorphVertex morphVertex : part){
283 Vertex vertex = morphVertex.getBaseVertex();
284 MorphVertex numbered = numberedMap.get(vertex);
285 assert numbered != null;
286 morphVertex.setSerialNumber(numbered.getSerialNumber());
296 * 各種オブジェクトの通し番号が変化する可能性がある。
298 public void trimming(){
299 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
300 this.surfaceList.clear();
301 this.surfaceList.addAll(trimmedSurfaceList);
303 List<Vertex> trimmedVertexList = trimmingVertexList();
304 this.vertexList.clear();
305 this.vertexList.addAll(trimmedVertexList);
312 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
313 * 所属マテリアルの無い面はリストの末端に配置される。
314 * 面リスト中のnullは削除され詰められる。
315 * @return トリミングされた面リスト
317 private List<Surface> trimmingSurfaceList(){
318 Set<Surface> materialedSurfaceSet = new HashSet<Surface>();
319 for(Material material : this.materialList){
320 if(material == null) continue;
321 for(Surface surface : material){
322 if(surface == null) continue;
323 materialedSurfaceSet.add(surface);
327 materialedSurfaceSet.removeAll(this.surfaceList);
329 List<Surface> result = new ArrayList<Surface>();
330 for(Surface surface : this.surfaceList){
331 if(surface == null) continue;
335 result.addAll(materialedSurfaceSet);
338 for(Surface surface : result){
339 surface.setSerialNumber(serialNum);
349 * 所属面の無い頂点はリストの末端に配置される。
350 * 頂点リスト中のnullは削除され詰められる。
351 * @return トリミングされた頂点リスト
353 private List<Vertex> trimmingVertexList(){
354 Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();
355 for(Surface surface : this.surfaceList){
356 if(surface == null) continue;
357 for(Vertex vertex : surface){
358 surfacedVertexSet.add(vertex);
362 surfacedVertexSet.removeAll(this.vertexList);
364 List<Vertex> result = new ArrayList<Vertex>();
365 for(Vertex vertex : this.vertexList){
366 if(vertex == null) continue;
370 result.addAll(surfacedVertexSet);
373 for(Vertex vertex : result){
374 vertex.setSerialNumber(serialNum);