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 private final I18nText modelName = new I18nText();
29 private final I18nText description = new I18nText();
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>();
35 private final List<BoneInfo> boneList = new ArrayList<BoneInfo>();
36 private final List<BoneGroup> boneGroupList = new ArrayList<BoneGroup>();
38 private final List<IKChain> ikChainList = new ArrayList<IKChain>();
40 private final Map<MorphType, List<MorphPart>> morphMap =
41 new EnumMap<MorphType, List<MorphPart>>(MorphType.class);
43 private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
44 private final List<RigidGroup> rigidGroupList =
45 new ArrayList<RigidGroup>();
47 private final List<JointInfo> jointList = new ArrayList<JointInfo>();
49 private ToonMap toonMap = new ToonMap();
57 assert this.vertexList instanceof RandomAccess;
58 assert this.surfaceList instanceof RandomAccess;
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>());
72 public I18nText getModelName(){
73 return this.modelName;
78 * 改行表現には{@literal \n}が用いられる
81 public I18nText getDescription(){
82 return this.description;
89 public List<Vertex> getVertexList(){
90 return this.vertexList;
97 public List<Surface> getSurfaceList(){
98 return this.surfaceList;
105 public List<Material> getMaterialList(){
106 return this.materialList;
113 public List<BoneInfo> getBoneList(){
114 return this.boneList;
121 public List<BoneGroup> getBoneGroupList(){
122 return this.boneGroupList;
129 public List<IKChain> getIKChainList(){
130 return this.ikChainList;
135 * @return 種類別モーフリストのマップ
137 public Map<MorphType, List<MorphPart>> getMorphMap(){
138 return this.morphMap;
145 public List<RigidInfo> getRigidList(){
146 return this.rigidList;
153 public List<RigidGroup> getRigidGroupList(){
154 return this.rigidGroupList;
159 * @return 剛体間ジョイントリスト
161 public List<JointInfo> getJointList(){
162 return this.jointList;
167 * @return トゥーンファイルマップ
169 public ToonMap getToonMap(){
175 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
176 * @param map トゥーンファイルマップ
178 public void setToonMap(ToonMap map){
180 for(Material material : this.materialList){
181 ShadeInfo info = material.getShadeInfo();
182 info.setToonMap(this.toonMap);
188 * このモデルがグローバル名を含むか判定する。
189 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
190 * @return グローバル名を持つならtrue
192 public boolean hasGlobalText(){
193 if(this.modelName.hasGlobalText()) return true;
194 if(this.description.hasGlobalText()) return true;
196 for(BoneInfo bone : this.boneList){
197 if(bone.getBoneName().hasGlobalText()) return true;
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;
209 for(BoneGroup group : this.boneGroupList){
210 if(group.getGroupName().hasGlobalText()) return true;
217 * モーフで使われる全てのモーフ頂点のリストを返す。
218 * モーフ間で重複する頂点はマージされる。
221 * 0から始まる通し番号がリナンバリングされる。
222 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
223 * @return モーフに使われるモーフ頂点のリスト
225 public List<MorphVertex> mergeMorphVertex(){
226 List<MorphVertex> result = new ArrayList<MorphVertex>();
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);
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);
249 Map<Vertex, MorphVertex> numberedMap =
250 new HashMap<Vertex, MorphVertex>();
251 for(MorphVertex morphVertex : result){
252 numberedMap.put(morphVertex.getBaseVertex(), morphVertex);
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());
274 * 各種オブジェクトの通し番号が変化する可能性がある。
276 public void trimming(){
277 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
278 this.surfaceList.clear();
279 this.surfaceList.addAll(trimmedSurfaceList);
281 List<Vertex> trimmedVertexList = trimmingVertexList();
282 this.vertexList.clear();
283 this.vertexList.addAll(trimmedVertexList);
290 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
291 * 所属マテリアルの無い面はリストの末端に配置される。
292 * 面リスト中のnullは削除され詰められる。
293 * @return トリミングされた面リスト
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);
305 materialedSurfaceSet.removeAll(this.surfaceList);
307 List<Surface> result = new ArrayList<Surface>();
308 for(Surface surface : this.surfaceList){
309 if(surface == null) continue;
313 result.addAll(materialedSurfaceSet);
316 for(Surface surface : result){
317 surface.setSerialNumber(serialNum);
327 * 所属面の無い頂点はリストの末端に配置される。
328 * 頂点リスト中のnullは削除され詰められる。
329 * @return トリミングされた頂点リスト
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);
340 surfacedVertexSet.removeAll(this.vertexList);
342 List<Vertex> result = new ArrayList<Vertex>();
343 for(Vertex vertex : this.vertexList){
344 if(vertex == null) continue;
348 result.addAll(surfacedVertexSet);
351 for(Vertex vertex : result){
352 vertex.setSerialNumber(serialNum);