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.sourceforge.mikutoga.corelib.I18nText;
21 import jp.sourceforge.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();
58 assert this.vertexList instanceof RandomAccess;
59 assert this.surfaceList instanceof RandomAccess;
61 this.morphMap.put(MorphType.EYEBROW, new ArrayList<MorphPart>());
62 this.morphMap.put(MorphType.EYE, new ArrayList<MorphPart>());
63 this.morphMap.put(MorphType.LIP, new ArrayList<MorphPart>());
64 this.morphMap.put(MorphType.EXTRA, new ArrayList<MorphPart>());
73 public I18nText getModelName(){
74 return this.modelName;
79 * 改行表現には{@literal \n}が用いられる
82 public I18nText getDescription(){
83 return this.description;
90 public List<Vertex> getVertexList(){
91 return this.vertexList;
98 public List<Surface> getSurfaceList(){
99 return this.surfaceList;
106 public List<Material> getMaterialList(){
107 return this.materialList;
114 public List<BoneInfo> getBoneList(){
115 return this.boneList;
122 public List<BoneGroup> getBoneGroupList(){
123 return this.boneGroupList;
130 public List<IKChain> getIKChainList(){
131 return this.ikChainList;
136 * @return 種類別モーフリストのマップ
138 public Map<MorphType, List<MorphPart>> getMorphMap(){
139 return this.morphMap;
146 public List<RigidInfo> getRigidList(){
147 return this.rigidList;
154 public List<RigidGroup> getRigidGroupList(){
155 return this.rigidGroupList;
160 * @return 剛体間ジョイントリスト
162 public List<JointInfo> getJointList(){
163 return this.jointList;
168 * @return トゥーンファイルマップ
170 public ToonMap getToonMap(){
176 * 各素材のシェーディングで参照するトゥーンファイルマップも更新される。
177 * @param map トゥーンファイルマップ
179 public void setToonMap(ToonMap map){
181 for(Material material : this.materialList){
182 ShadeInfo info = material.getShadeInfo();
183 info.setToonMap(this.toonMap);
189 * このモデルがグローバル名を含むか判定する。
190 * ボーン名、ボーングループ名、モーフ名、モデル説明文が判定対象。
191 * @return グローバル名を持つならtrue
193 public boolean hasGlobalText(){
194 if(this.modelName.hasGlobalText()) return true;
195 if(this.description.hasGlobalText()) return true;
197 for(BoneInfo bone : this.boneList){
198 if(bone.getBoneName().hasGlobalText()) return true;
201 List<MorphType> typeList = new ArrayList<MorphType>();
202 typeList.addAll(this.morphMap.keySet());
203 for(MorphType type : typeList){
204 List<MorphPart> partList = this.morphMap.get(type);
205 for(MorphPart part : partList){
206 if(part.getMorphName().hasGlobalText()) return true;
210 for(BoneGroup group : this.boneGroupList){
211 if(group.getGroupName().hasGlobalText()) return true;
218 * モーフで使われる全てのモーフ頂点のリストを返す。
219 * モーフ間で重複する頂点はマージされる。
222 * 0から始まる通し番号がリナンバリングされる。
223 * 通し番号は返されるモーフ頂点リストの添え字番号と一致する。
224 * @return モーフに使われるモーフ頂点のリスト
226 public List<MorphVertex> mergeMorphVertex(){
227 List<MorphVertex> result = new ArrayList<MorphVertex>();
229 Set<Vertex> mergedVertexSet = new HashSet<Vertex>();
230 for(MorphType type : this.morphMap.keySet()){
231 if(type.isBase()) continue;
232 List<MorphPart> partList = this.morphMap.get(type);
233 if(partList == null) continue;
234 for(MorphPart part : partList){
235 for(MorphVertex morphVertex : part){
236 Vertex vertex = morphVertex.getBaseVertex();
237 if(mergedVertexSet.contains(vertex)) continue;
238 mergedVertexSet.add(vertex);
239 result.add(morphVertex);
244 Collections.sort(result, MorphVertex.VIDCOMPARATOR);
245 for(int idx = 0; idx < result.size(); idx++){
246 MorphVertex morphVertex = result.get(idx);
247 morphVertex.setSerialNumber(idx);
250 Map<Vertex, MorphVertex> numberedMap =
251 new HashMap<Vertex, MorphVertex>();
252 for(MorphVertex morphVertex : result){
253 numberedMap.put(morphVertex.getBaseVertex(), morphVertex);
256 for(MorphType type : this.morphMap.keySet()){
257 if(type.isBase()) continue;
258 List<MorphPart> partList = this.morphMap.get(type);
259 if(partList == null) continue;
260 for(MorphPart part : partList){
261 for(MorphVertex morphVertex : part){
262 Vertex vertex = morphVertex.getBaseVertex();
263 MorphVertex numbered = numberedMap.get(vertex);
264 assert numbered != null;
265 morphVertex.setSerialNumber(numbered.getSerialNumber());
275 * 各種オブジェクトの通し番号が変化する可能性がある。
277 public void trimming(){
278 List<Surface> trimmedSurfaceList = trimmingSurfaceList();
279 this.surfaceList.clear();
280 this.surfaceList.addAll(trimmedSurfaceList);
282 List<Vertex> trimmedVertexList = trimmingVertexList();
283 this.vertexList.clear();
284 this.vertexList.addAll(trimmedVertexList);
291 * 所属マテリアル順に再配置し、通し番号を割り振り直す。
292 * 所属マテリアルの無い面はリストの末端に配置される。
293 * 面リスト中のnullは削除され詰められる。
294 * @return トリミングされた面リスト
296 private List<Surface> trimmingSurfaceList(){
297 Set<Surface> materialedSurfaceSet = new HashSet<Surface>();
298 for(Material material : this.materialList){
299 if(material == null) continue;
300 for(Surface surface : material){
301 if(surface == null) continue;
302 materialedSurfaceSet.add(surface);
306 materialedSurfaceSet.removeAll(this.surfaceList);
308 List<Surface> result = new ArrayList<Surface>();
309 for(Surface surface : this.surfaceList){
310 if(surface == null) continue;
314 result.addAll(materialedSurfaceSet);
317 for(Surface surface : result){
318 surface.setSerialNumber(serialNum);
328 * 所属面の無い頂点はリストの末端に配置される。
329 * 頂点リスト中のnullは削除され詰められる。
330 * @return トリミングされた頂点リスト
332 private List<Vertex> trimmingVertexList(){
333 Set<Vertex> surfacedVertexSet = new HashSet<Vertex>();
334 for(Surface surface : this.surfaceList){
335 if(surface == null) continue;
336 for(Vertex vertex : surface){
337 surfacedVertexSet.add(vertex);
341 surfacedVertexSet.removeAll(this.vertexList);
343 List<Vertex> result = new ArrayList<Vertex>();
344 for(Vertex vertex : this.vertexList){
345 if(vertex == null) continue;
349 result.addAll(surfacedVertexSet);
352 for(Vertex vertex : result){
353 vertex.setSerialNumber(serialNum);