OSDN Git Service

テストセット整備
[mikutoga/Pmd2XML.git] / src / main / java / jp / sfjp / mikutoga / pmd / xml / XmlLoader.java
1 /*
2  * xml loader
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.pmd.xml;
9
10 import java.awt.Color;
11 import java.io.IOException;
12 import java.text.MessageFormat;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.LinkedList;
17 import java.util.List;
18 import java.util.Map;
19 import javax.xml.parsers.DocumentBuilder;
20 import jp.sfjp.mikutoga.pmd.model.BoneGroup;
21 import jp.sfjp.mikutoga.pmd.model.BoneInfo;
22 import jp.sfjp.mikutoga.pmd.model.DynamicsInfo;
23 import jp.sfjp.mikutoga.pmd.model.IKChain;
24 import jp.sfjp.mikutoga.pmd.model.JointInfo;
25 import jp.sfjp.mikutoga.pmd.model.ListUtil;
26 import jp.sfjp.mikutoga.pmd.model.Material;
27 import jp.sfjp.mikutoga.pmd.model.MorphPart;
28 import jp.sfjp.mikutoga.pmd.model.MorphVertex;
29 import jp.sfjp.mikutoga.pmd.model.PmdModel;
30 import jp.sfjp.mikutoga.pmd.model.RigidGroup;
31 import jp.sfjp.mikutoga.pmd.model.RigidInfo;
32 import jp.sfjp.mikutoga.pmd.model.RigidShape;
33 import jp.sfjp.mikutoga.pmd.model.ShadeInfo;
34 import jp.sfjp.mikutoga.pmd.model.Surface;
35 import jp.sfjp.mikutoga.pmd.model.ToonMap;
36 import jp.sfjp.mikutoga.pmd.model.Vertex;
37 import jp.sourceforge.mikutoga.corelib.I18nText;
38 import jp.sourceforge.mikutoga.math.MkPos2D;
39 import jp.sourceforge.mikutoga.math.MkPos3D;
40 import jp.sourceforge.mikutoga.math.MkVec3D;
41 import jp.sourceforge.mikutoga.pmd.BoneType;
42 import jp.sourceforge.mikutoga.pmd.Deg3d;
43 import jp.sourceforge.mikutoga.pmd.MorphType;
44 import jp.sourceforge.mikutoga.pmd.Rad3d;
45 import jp.sourceforge.mikutoga.pmd.RigidBehaviorType;
46 import jp.sourceforge.mikutoga.pmd.RigidShapeType;
47 import jp.sourceforge.mikutoga.pmd.TripletRange;
48 import jp.sourceforge.mikutoga.xml.DomNsUtils;
49 import jp.sourceforge.mikutoga.xml.DomUtils;
50 import jp.sourceforge.mikutoga.xml.TogaXmlException;
51 import org.w3c.dom.Document;
52 import org.w3c.dom.Element;
53 import org.w3c.dom.Node;
54 import org.xml.sax.InputSource;
55 import org.xml.sax.SAXException;
56
57 /**
58  * XML形式でのモデルファイルを読み込む。
59  */
60 public class XmlLoader {
61
62     private static final String ERR_INVROOT =
63             "invalid root element[{0}]";
64     private static final String ERR_UKVER =
65             "unknown schema version[{0}]";
66
67
68     private PmdModel model;
69
70     private final Map<String, Integer> toonIdxMap =
71             new HashMap<String, Integer>();
72     private final Map<String, BoneInfo> boneMap =
73             new HashMap<String, BoneInfo>();
74     private final Map<String, Vertex> vertexMap =
75             new HashMap<String, Vertex>();
76     private final Map<String, List<Surface>> surfaceGroupMap =
77             new HashMap<String, List<Surface>>();
78     private final Map<String, RigidInfo> rigidMap =
79             new HashMap<String, RigidInfo>();
80     private final Map<String, RigidGroup> rigidGroupMap =
81             new HashMap<String, RigidGroup>();
82
83     private String rootNamespace = Schema130128.NS_PMDXML;
84     private XmlModelFileType fileType = XmlModelFileType.XML_AUTO;
85
86
87     /**
88      * コンストラクタ。
89      */
90     public XmlLoader(){
91         super();
92         return;
93     }
94
95
96     /**
97      * 要素からxsd:string型属性値を読み取る。
98      * @param elem 要素
99      * @param attrName 属性名
100      * @return 文字列
101      * @throws TogaXmlException 属性値が見つからなかった。
102      */
103     private static String getStringAttr(Element elem, String attrName)
104             throws TogaXmlException{
105         return DomUtils.getStringAttr(elem, attrName);
106     }
107
108     /**
109      * 要素からxsd:boolean型属性値を読み取る。
110      * @param elem 要素
111      * @param attrName 属性名
112      * @return 真ならtrue
113      * @throws TogaXmlException 属性値が見つからなかった。
114      */
115     private static boolean getBooleanAttr(Element elem, String attrName)
116             throws TogaXmlException{
117         return DomUtils.getBooleanAttr(elem, attrName);
118     }
119
120     /**
121      * 要素からxsd:integer型属性値を読み取る。
122      * @param elem 要素
123      * @param attrName 属性名
124      * @return int値
125      * @throws TogaXmlException 属性値が見つからなかった。
126      */
127     private static int getIntegerAttr(Element elem, String attrName)
128             throws TogaXmlException{
129         return DomUtils.getIntegerAttr(elem, attrName);
130     }
131
132     /**
133      * 要素からxsd:float型属性値を読み取る。
134      * @param elem 要素
135      * @param attrName 属性名
136      * @return float値
137      * @throws TogaXmlException 属性値が見つからなかった。
138      */
139     private static float getFloatAttr(Element elem, String attrName)
140             throws TogaXmlException{
141         return DomUtils.getFloatAttr(elem, attrName);
142     }
143
144     /**
145      * 要素から日本語Windows用ファイル名を属性値として読み取る。
146      * 念のため文字U+00A5は文字U-005Cに変換される。
147      * @param elem 要素
148      * @param attrName 属性名
149      * @return ファイル名
150      * @throws TogaXmlException 属性値が見つからなかった。
151      */
152     private static String getSjisFileNameAttr(Element elem, String attrName)
153             throws TogaXmlException{
154         return DomUtils.getSjisFileNameAttr(elem, attrName);
155     }
156
157     /**
158      * brタグで区切られた文字列内容(Mixed content)を
159      * 改行付き文字列に変換する。
160      * brタグはその出現回数だけ\nに変換される。
161      * 生文字列コンテンツ中の\n,\rは削除される。
162      * 改行文字以外のホワイトスペースは保持される。
163      * @param parent br要素及び文字列コンテンツを含む要素
164      * @return 変換された文字列
165      */
166     private static String getBRedContent(Element parent){
167         StringBuilder result = new StringBuilder();
168
169         for(Node node = parent.getFirstChild();
170             node != null;
171             node = node.getNextSibling() ){
172
173             switch(node.getNodeType()){
174             case Node.ELEMENT_NODE:
175                 Element elem = (Element) node;
176                 if("br".equals(elem.getTagName())){
177                     result.append('\n');
178                 }
179                 break;
180             case Node.TEXT_NODE:
181             case Node.CDATA_SECTION_NODE:
182                 String content = node.getTextContent();
183                 content = content.replace("\r", "");
184                 content = content.replace("\n", "");
185                 result.append(content);
186                 break;
187             default:
188                 break;
189             }
190         }
191
192         return result.toString();
193     }
194
195
196     /**
197      * パース中のXMLファイル種別を返す。
198      * @return ファイル種別
199      */
200     private XmlModelFileType getFileType(){
201         return this.fileType;
202     }
203
204     /**
205      * パース中のXMLファイル種別を設定する。
206      * @param type 具体的なファイル種別
207      */
208     private void setFileType(XmlModelFileType type){
209         if(   type != XmlModelFileType.XML_101009
210            && type != XmlModelFileType.XML_130128 ){
211             throw new IllegalArgumentException();
212         }
213         this.fileType = type;
214         return;
215     }
216
217     /**
218      * ルート要素の名前空間URIを返す。
219      * @return 名前空間URI。nullなら名前空間が無いと見なされる
220      */
221     private String getRootNamespace(){
222         return this.rootNamespace;
223     }
224
225     /**
226      * ルート要素の名前空間URIを設定する。
227      * @param name 名前空間URI。nullなら名前空間が無いと見なされる
228      */
229     private void setRootNamespace(String name){
230         this.rootNamespace = name;
231         return;
232     }
233
234     /**
235      * 指定された名前の子要素を1つだけ返す。
236      * @param parent 親要素
237      * @param tagName 子要素名
238      * @return 子要素
239      * @throws TogaXmlException 1つも見つからなかった
240      */
241     private Element getChild(Element parent, String tagName)
242             throws TogaXmlException{
243         String ns = getRootNamespace();
244         Element result = DomNsUtils.getFirstChild(parent, ns, tagName);
245         return result;
246     }
247
248     /**
249      * 親要素が指定された名前の子要素を持つか判定する。
250      * @param parent 親要素
251      * @param tagName 子要素名
252      * @return 指定名の子要素が存在すればtrue
253      */
254     private boolean hasChild(Element parent, String tagName){
255         String ns = getRootNamespace();
256         return DomNsUtils.hasChild(parent, ns, tagName);
257     }
258
259     /**
260      * 指定された名前の子要素のforeachを返す。
261      * @param parent 親要素
262      * @param childTag 子要素名
263      * @return 子要素のforeach
264      */
265     private Iterable<Element> eachChild(Element parent,
266                                          String childTag){
267         String ns = getRootNamespace();
268         return DomNsUtils.getEachChild(parent, ns, childTag);
269     }
270
271     /**
272      * 多言語名を取得する。
273      * @param baseElement 元要素
274      * @param text 多言語名格納先
275      * @throws TogaXmlException あるべき属性が存在しない。
276      */
277     private void buildI18nName(Element baseElement, I18nText text)
278             throws TogaXmlException{
279         String primaryText;
280         primaryText = getStringAttr(baseElement, "name");
281         text.setPrimaryText(primaryText);
282
283         for(Element i18nNameElem : eachChild(baseElement, "i18nName")){
284             String lang = getStringAttr(i18nNameElem, "lang");
285             String name = getStringAttr(i18nNameElem, "name");
286             if("en".equals(lang)){
287                 text.setGlobalText(name);
288             }else{
289                 text.setI18nText(lang, text);
290             }
291         }
292
293         return;
294     }
295
296     /**
297      * XMLのパースを開始する。
298      * @param builder ドキュメントビルダ
299      * @param source XML入力
300      * @return モデルデータ
301      * @throws SAXException 構文エラー
302      * @throws IOException 入力エラー
303      * @throws TogaXmlException 構文エラー
304      */
305     public PmdModel parse(DocumentBuilder builder, InputSource source)
306             throws SAXException, IOException, TogaXmlException{
307         Document document = builder.parse(source);
308         PmdModel result = parse(document);
309         return result;
310     }
311
312     /**
313      * XMLのパースを開始する。
314      * @param document DOMドキュメント
315      * @return モデルデータ
316      * @throws TogaXmlException 構文エラー
317      */
318     public PmdModel parse(Document document)
319             throws TogaXmlException{
320         this.model = new PmdModel();
321
322         Element pmdModelElem = document.getDocumentElement();
323         String namespace = pmdModelElem.getNamespaceURI();
324         setRootNamespace(namespace);
325
326         buildBasicInfo(pmdModelElem);
327
328         buildBoneList(pmdModelElem);
329         buildVertexList(pmdModelElem);
330         buildSurfaceList(pmdModelElem);
331
332         buildToonMap(pmdModelElem);
333         buildMaterialList(pmdModelElem);
334         buildIkChainList(pmdModelElem);
335         buildMorphList(pmdModelElem);
336         buildBoneGroupList(pmdModelElem);
337
338         buildRigidList(pmdModelElem);
339         buildRigidGroupList(pmdModelElem);
340         resolveThroughRigidGroup(pmdModelElem);
341
342         buildJointList(pmdModelElem);
343
344         return this.model;
345     }
346
347     /**
348      * DOMからモデル基本情報を組み立てる。
349      * @param pmdModelElem ルート要素
350      * @throws TogaXmlException 構文エラー
351      */
352     private void buildBasicInfo(Element pmdModelElem)
353             throws TogaXmlException{
354         if( ! DomNsUtils.hasNsLocalNameElem(pmdModelElem,
355                                             getRootNamespace(),
356                                             "pmdModel") ){
357             String tagName = pmdModelElem.getTagName();
358             String msg = MessageFormat.format(ERR_INVROOT, tagName);
359             throw new TogaXmlException(msg);
360         }
361
362         String version = getStringAttr(pmdModelElem, "schemaVersion");
363         if(Schema101009.VER_PMDXML.equals(version)){
364             setFileType(XmlModelFileType.XML_101009);
365         }else if(Schema130128.VER_PMDXML.equals(version)){
366             setFileType(XmlModelFileType.XML_130128);
367         }else{
368             String msg = MessageFormat.format(ERR_UKVER, version);
369             throw new TogaXmlException(msg);
370         }
371
372         I18nText modelName = this.model.getModelName();
373         buildI18nName(pmdModelElem, modelName);
374
375         String primaryDescription = null;
376         String globalDescription = null;
377         for(Element descriptionElem :
378             eachChild(pmdModelElem, "description")){
379             String descriptionText = getBRedContent(descriptionElem);
380             if( ! descriptionElem.hasAttribute("lang") ){
381                 primaryDescription = descriptionText;
382             }else{
383                 String lang = getStringAttr(descriptionElem, "lang");
384                 if(lang.equals("ja")){
385                     primaryDescription = descriptionText;
386                 }else if(lang.equals("en")){
387                     globalDescription = descriptionText;
388                 }
389             }
390         }
391
392         I18nText description = this.model.getDescription();
393         description.setPrimaryText(primaryDescription);
394         description.setGlobalText(globalDescription);
395
396         return;
397     }
398
399     /**
400      * DOMからボーンリスト情報を組み立てる。
401      * @param pmdModelElem ルート要素
402      * @throws TogaXmlException 構文エラー
403      */
404     private void buildBoneList(Element pmdModelElem)
405             throws TogaXmlException{
406         Element boneListElem = getChild(pmdModelElem, "boneList");
407
408         List<BoneInfo> boneList = this.model.getBoneList();
409
410         for(Element boneElem : eachChild(boneListElem, "bone")){
411             BoneInfo boneInfo = new BoneInfo();
412             boneList.add(boneInfo);
413
414             I18nText boneName = boneInfo.getBoneName();
415             buildI18nName(boneElem, boneName);
416
417             String boneType = getStringAttr(boneElem, "type");
418             BoneType type = BoneType.valueOf(boneType);
419             boneInfo.setBoneType(type);
420
421             String boneId = getStringAttr(boneElem, "boneId");
422             this.boneMap.put(boneId, boneInfo);
423
424             Element positionElem = getChild(boneElem, "position");
425             float xPos = getFloatAttr(positionElem, "x");
426             float yPos = getFloatAttr(positionElem, "y");
427             float zPos = getFloatAttr(positionElem, "z");
428             MkPos3D position = boneInfo.getPosition();
429             position.setXpos(xPos);
430             position.setYpos(yPos);
431             position.setZpos(zPos);
432         }
433
434         ListUtil.assignIndexedSerial(boneList);
435
436         Iterator<BoneInfo> bit = boneList.iterator();
437         for(Element boneElem : eachChild(boneListElem, "bone")){
438             BoneInfo boneInfo = bit.next();
439
440             if(hasChild(boneElem, "ikBone")){            // 101009 only
441                 Element ikBoneElem = getChild(boneElem, "ikBone");
442                 String ikBoneId = getStringAttr(ikBoneElem, "boneIdRef");
443                 BoneInfo ikBone = this.boneMap.get(ikBoneId);
444                 boneInfo.setSrcBone(ikBone);
445             }else if(hasChild(boneElem, "sourceBone")){  // 130128 only
446                 Element srcBoneElem = getChild(boneElem, "sourceBone");
447                 String srcBoneId = getStringAttr(srcBoneElem, "boneIdRef");
448                 BoneInfo srcBone = this.boneMap.get(srcBoneId);
449                 boneInfo.setSrcBone(srcBone);
450             }else if(hasChild(boneElem, "rotationRatio")){
451                 Element rotElem = getChild(boneElem, "rotationRatio");
452                 int ratio = getIntegerAttr(rotElem, "ratio");
453                 boneInfo.setRotationRatio(ratio);
454             }
455
456             Element boneChainElem = getChild(boneElem, "boneChain");
457             if(boneChainElem.hasAttribute("prevBoneIdRef")){
458                 String prevId = getStringAttr(boneChainElem, "prevBoneIdRef");
459                 BoneInfo prevBone = this.boneMap.get(prevId);
460                 boneInfo.setPrevBone(prevBone);
461             }
462             if(boneChainElem.hasAttribute("nextBoneIdRef")){
463                 String nextId = getStringAttr(boneChainElem, "nextBoneIdRef");
464                 BoneInfo nextBone = this.boneMap.get(nextId);
465                 boneInfo.setNextBone(nextBone);
466             }
467         }
468
469         return;
470     }
471
472     /**
473      * DOMから頂点リスト情報を組み立てる。
474      * @param pmdModelElem ルート要素
475      * @throws TogaXmlException 構文エラー
476      */
477     private void buildVertexList(Element pmdModelElem)
478             throws TogaXmlException{
479         Element vertexListElem = getChild(pmdModelElem, "vertexList");
480
481         List<Vertex> vertexList = this.model.getVertexList();
482
483         for(Element vertexElem : eachChild(vertexListElem, "vertex")){
484             Vertex vertex = new Vertex();
485             vertexList.add(vertex);
486
487             String vertexId = getStringAttr(vertexElem, "vtxId");
488             this.vertexMap.put(vertexId, vertex);
489
490             boolean showEdge = getBooleanAttr(vertexElem, "showEdge");
491             vertex.setEdgeAppearance(showEdge);
492
493             float xVal;
494             float yVal;
495             float zVal;
496
497             Element positionElem = getChild(vertexElem, "position");
498             xVal = getFloatAttr(positionElem, "x");
499             yVal = getFloatAttr(positionElem, "y");
500             zVal = getFloatAttr(positionElem, "z");
501             MkPos3D position = vertex.getPosition();
502             position.setXpos(xVal);
503             position.setYpos(yVal);
504             position.setZpos(zVal);
505
506             Element normalElem = getChild(vertexElem, "normal");
507             xVal = getFloatAttr(normalElem, "x");
508             yVal = getFloatAttr(normalElem, "y");
509             zVal = getFloatAttr(normalElem, "z");
510             MkVec3D normal = vertex.getNormal();
511             normal.setXVal(xVal);
512             normal.setYVal(yVal);
513             normal.setZVal(zVal);
514
515             Element uvElem = getChild(vertexElem, "uvMap");
516             float uVal = getFloatAttr(uvElem, "u");
517             float vVal = getFloatAttr(uvElem, "v");
518             MkPos2D uv = vertex.getUVPosition();
519             uv.setXpos(uVal);
520             uv.setYpos(vVal);
521
522             Element skinningElem = getChild(vertexElem, "skinning");
523             String boneId1 = getStringAttr(skinningElem, "boneIdRef1");
524             String boneId2 = getStringAttr(skinningElem, "boneIdRef2");
525             int weight = getIntegerAttr(skinningElem, "weightBalance");
526             BoneInfo boneA = this.boneMap.get(boneId1);
527             BoneInfo boneB = this.boneMap.get(boneId2);
528             vertex.setBonePair(boneA, boneB);
529             vertex.setWeightA(weight);
530         }
531
532         ListUtil.assignIndexedSerial(vertexList);
533
534         return;
535     }
536
537     /**
538      * DOMからポリゴンリスト情報を組み立てる。
539      * @param pmdModelElem ルート要素
540      * @throws TogaXmlException 構文エラー
541      */
542     private void buildSurfaceList(Element pmdModelElem)
543             throws TogaXmlException{
544         Element surfaceGroupListElem =
545                 getChild(pmdModelElem, "surfaceGroupList");
546
547         for(Element surfaceGroupElem :
548             eachChild(surfaceGroupListElem, "surfaceGroup") ){
549
550             String groupId =
551                     getStringAttr(surfaceGroupElem, "surfaceGroupId");
552             List<Surface> surfaceList = buildSurface(surfaceGroupElem);
553
554             this.surfaceGroupMap.put(groupId, surfaceList);
555         }
556
557         return;
558     }
559
560     /**
561      * DOMからポリゴン情報を組み立てる。
562      * @param surfaceGroupElem surfaceGroup要素
563      * @return ポリゴンリスト
564      * @throws TogaXmlException 構文エラー
565      */
566     private List<Surface> buildSurface(Element surfaceGroupElem)
567             throws TogaXmlException{
568         List<Surface> result = new ArrayList<Surface>();
569
570         for(Element surfaceElem : eachChild(surfaceGroupElem, "surface")){
571             Surface surface = new Surface();
572             result.add(surface);
573
574             String id1 = getStringAttr(surfaceElem, "vtxIdRef1");
575             String id2 = getStringAttr(surfaceElem, "vtxIdRef2");
576             String id3 = getStringAttr(surfaceElem, "vtxIdRef3");
577
578             Vertex vertex1 = this.vertexMap.get(id1);
579             Vertex vertex2 = this.vertexMap.get(id2);
580             Vertex vertex3 = this.vertexMap.get(id3);
581
582             surface.setTriangle(vertex1, vertex2, vertex3);
583         }
584
585         return result;
586     }
587
588     /**
589      * DOMからトゥーンマップ情報を組み立てる。
590      * @param pmdModelElem ルート要素
591      * @throws TogaXmlException 構文エラー
592      */
593     private void buildToonMap(Element pmdModelElem)
594             throws TogaXmlException{
595         ToonMap toonMap = this.model.getToonMap();
596
597         Element toonMapElem = getChild(pmdModelElem, "toonMap");
598
599         for(Element toonDefElem : eachChild(toonMapElem, "toonDef")){
600             String toonFileId = getStringAttr(toonDefElem, "toonFileId");
601             int toonIndex = getIntegerAttr(toonDefElem, "index");
602             String toonFile = getSjisFileNameAttr(toonDefElem, "winFileName");
603
604             toonMap.setIndexedToon(toonIndex, toonFile);
605             this.toonIdxMap.put(toonFileId, toonIndex);
606         }
607
608         return;
609     }
610
611     /**
612      * DOMからマテリアル情報を組み立てる。
613      * @param pmdModelElem ルート要素
614      * @throws TogaXmlException 構文エラー
615      */
616     private void buildMaterialList(Element pmdModelElem)
617             throws TogaXmlException{
618         Element materialListElem =
619                 getChild(pmdModelElem, "materialList");
620
621         List<Surface> surfaceList = this.model.getSurfaceList();
622         List<Material> materialList = this.model.getMaterialList();
623
624         for(Element materialElem : eachChild(materialListElem, "material")){
625             Material material = new Material();
626             materialList.add(material);
627
628             material.getShadeInfo().setToonMap(this.model.getToonMap());
629
630             String surfaceGroupId =
631                     getStringAttr(materialElem, "surfaceGroupIdRef");
632             List<Surface> surfaceGroup =
633                     this.surfaceGroupMap.get(surfaceGroupId);
634             surfaceList.addAll(surfaceGroup);
635             material.getSurfaceList().addAll(surfaceGroup);
636
637             boolean hasEdge = getBooleanAttr(materialElem, "showEdge");
638             material.setEdgeAppearance(hasEdge);
639
640             ShadeInfo shadeInfo = material.getShadeInfo();
641
642             int toonIdx;
643             if(hasChild(materialElem, "toon")){
644                 Element toonElem = getChild(materialElem, "toon");
645                 String toonId = getStringAttr(toonElem, "toonFileIdRef");
646                 toonIdx = this.toonIdxMap.get(toonId);
647             }else{
648                 toonIdx = 255;
649             }
650             shadeInfo.setToonIndex(toonIdx);
651
652             if(hasChild(materialElem, "textureFile")){
653                 Element textureFileElem =
654                         getChild(materialElem, "textureFile");
655                 String textureFile =
656                         getSjisFileNameAttr(textureFileElem, "winFileName");
657                 shadeInfo.setTextureFileName(textureFile);
658             }
659
660             if(hasChild(materialElem, "spheremapFile")){
661                 Element spheremapFileElem =
662                         getChild(materialElem, "spheremapFile");
663                 String spheremapFile =
664                         getSjisFileNameAttr(spheremapFileElem, "winFileName");
665                 shadeInfo.setSpheremapFileName(spheremapFile);
666             }
667
668             float red;
669             float green;
670             float blue;
671
672             Element diffuseElem = getChild(materialElem, "diffuse");
673             red   = getFloatAttr(diffuseElem, "r");
674             green = getFloatAttr(diffuseElem, "g");
675             blue  = getFloatAttr(diffuseElem, "b");
676             float alpha = getFloatAttr(diffuseElem, "alpha");
677             Color diffuse = new Color(red, green, blue, alpha);
678             material.setDiffuseColor(diffuse);
679
680             Element specularElem = getChild(materialElem, "specular");
681             red   = getFloatAttr(specularElem, "r");
682             green = getFloatAttr(specularElem, "g");
683             blue  = getFloatAttr(specularElem, "b");
684             float shininess = getFloatAttr(specularElem, "shininess");
685             Color specular = new Color(red, green, blue);
686             material.setSpecularColor(specular);
687             material.setShininess(shininess);
688
689             Element ambientElem = getChild(materialElem, "ambient");
690             red   = getFloatAttr(ambientElem, "r");
691             green = getFloatAttr(ambientElem, "g");
692             blue  = getFloatAttr(ambientElem, "b");
693             Color ambient = new Color(red, green, blue);
694             material.setAmbientColor(ambient);
695         }
696
697         return;
698     }
699
700     /**
701      * DOMからIKチェーンリスト情報を組み立てる。
702      * @param pmdModelElem ルート要素
703      * @throws TogaXmlException 構文エラー
704      */
705     private void buildIkChainList(Element pmdModelElem)
706             throws TogaXmlException{
707         Element ikChainListElem =
708                 getChild(pmdModelElem, "ikChainList");
709
710         List<IKChain> ikChainList = this.model.getIKChainList();
711
712         for(Element ikChainElem : eachChild(ikChainListElem, "ikChain")){
713             IKChain ikChain = new IKChain();
714             ikChainList.add(ikChain);
715
716             String ikBoneIdRef = getStringAttr(ikChainElem, "ikBoneIdRef");
717             int rucursiveDepth =
718                     getIntegerAttr(ikChainElem, "recursiveDepth");
719             float weight = getFloatAttr(ikChainElem, "weight");
720
721             BoneInfo ikBone = this.boneMap.get(ikBoneIdRef);
722             ikChain.setIkBone(ikBone);
723             ikChain.setIKDepth(rucursiveDepth);
724             ikChain.setIKWeight(weight);
725
726             List<BoneInfo> chainList = ikChain.getChainedBoneList();
727
728             for(Element orderElem : eachChild(ikChainElem, "chainOrder")){
729                 String boneIdRef = getStringAttr(orderElem, "boneIdRef");
730                 BoneInfo chaindBone = this.boneMap.get(boneIdRef);
731                 chainList.add(chaindBone);
732             }
733         }
734
735         return;
736     }
737
738     /**
739      * DOMからモーフリスト情報を組み立てる。
740      * @param pmdModelElem ルート要素
741      * @throws TogaXmlException 構文エラー
742      */
743     private void buildMorphList(Element pmdModelElem)
744             throws TogaXmlException{
745         Element morphListElem =
746                 getChild(pmdModelElem, "morphList");
747
748         Map<MorphType, List<MorphPart>> morphMap = this.model.getMorphMap();
749
750         for(Element morphElem : eachChild(morphListElem, "morph")){
751             MorphPart morphPart = new MorphPart();
752
753             I18nText name = morphPart.getMorphName();
754             buildI18nName(morphElem, name);
755
756             String type = getStringAttr(morphElem, "type");
757             MorphType morphType = MorphType.valueOf(type);
758             morphPart.setMorphType(morphType);
759
760             List<MorphVertex> morphVertexList =
761                     morphPart.getMorphVertexList();
762
763             for(Element morphVertexElem
764                     : eachChild(morphElem, "morphVertex")){
765                 String vtxIdRef = getStringAttr(morphVertexElem, "vtxIdRef");
766                 Vertex baseVertex = this.vertexMap.get(vtxIdRef);
767                 float xOff = getFloatAttr(morphVertexElem, "xOff");
768                 float yOff = getFloatAttr(morphVertexElem, "yOff");
769                 float zOff = getFloatAttr(morphVertexElem, "zOff");
770
771                 MorphVertex morphVertex = new MorphVertex();
772                 morphVertex.setBaseVertex(baseVertex);
773                 MkPos3D position = morphVertex.getOffset();
774                 position.setXpos(xOff);
775                 position.setYpos(yOff);
776                 position.setZpos(zOff);
777
778                 morphVertexList.add(morphVertex);
779             }
780
781             morphMap.get(morphType).add(morphPart);
782         }
783
784         List<MorphPart> serialList = new LinkedList<MorphPart>();
785         MorphPart baseDummy = new MorphPart();
786         serialList.add(baseDummy);
787         for(MorphPart part : morphMap.get(MorphType.EYEBROW)){
788             serialList.add(part);
789         }
790         for(MorphPart part : morphMap.get(MorphType.EYE)){
791             serialList.add(part);
792         }
793         for(MorphPart part : morphMap.get(MorphType.LIP)){
794             serialList.add(part);
795         }
796         for(MorphPart part : morphMap.get(MorphType.EXTRA)){
797             serialList.add(part);
798         }
799         ListUtil.assignIndexedSerial(serialList);
800
801         return;
802     }
803
804     /**
805      * DOMからボーングループ情報を組み立てる。
806      * @param pmdModelElem ルート要素
807      * @throws TogaXmlException 構文エラー
808      */
809     private void buildBoneGroupList(Element pmdModelElem)
810             throws TogaXmlException{
811         Element boneGroupListElem =
812                 getChild(pmdModelElem, "boneGroupList");
813
814         List<BoneGroup> boneGroupList = this.model.getBoneGroupList();
815         BoneGroup defaultGroup = new BoneGroup();
816         boneGroupList.add(defaultGroup);
817
818         for(Element boneGroupElem
819                 : eachChild(boneGroupListElem, "boneGroup")){
820             BoneGroup group = new BoneGroup();
821             boneGroupList.add(group);
822
823             I18nText name = group.getGroupName();
824             buildI18nName(boneGroupElem, name);
825
826             for(Element boneGroupMemberElem
827                     : eachChild(boneGroupElem, "boneGroupMember")){
828                 String boneIdRef =
829                         getStringAttr(boneGroupMemberElem, "boneIdRef");
830                 BoneInfo bone = this.boneMap.get(boneIdRef);
831                 group.getBoneList().add(bone);
832             }
833         }
834
835         ListUtil.assignIndexedSerial(boneGroupList);
836
837         return;
838     }
839
840     /**
841      * DOMから剛体リスト情報を組み立てる。
842      * @param pmdModelElem ルート要素
843      * @throws TogaXmlException 構文エラー
844      */
845     private void buildRigidList(Element pmdModelElem)
846             throws TogaXmlException{
847         Element rigidListElem =
848                 getChild(pmdModelElem, "rigidList");
849
850         List<RigidInfo> rigidList = this.model.getRigidList();
851
852         for(Element rigidElem : eachChild(rigidListElem, "rigid")){
853             RigidInfo rigid = new RigidInfo();
854             rigidList.add(rigid);
855
856             I18nText name = rigid.getRigidName();
857             buildI18nName(rigidElem, name);
858
859             String behavior = getStringAttr(rigidElem, "behavior");
860             RigidBehaviorType type = RigidBehaviorType.valueOf(behavior);
861             rigid.setBehaviorType(type);
862
863             String rigidId = getStringAttr(rigidElem, "rigidId");
864             this.rigidMap.put(rigidId, rigid);
865
866             if(hasChild(rigidElem, "linkedBone")){
867                 Element linkedBoneElem = getChild(rigidElem, "linkedBone");
868                 String boneIdRef = getStringAttr(linkedBoneElem, "boneIdRef");
869                 BoneInfo linkedBone = this.boneMap.get(boneIdRef);
870                 rigid.setLinkedBone(linkedBone);
871             }
872
873             RigidShape rigidShape = rigid.getRigidShape();
874             if(hasChild(rigidElem, "rigidShapeSphere")){
875                 Element shapeElem =
876                         getChild(rigidElem, "rigidShapeSphere");
877                 float radius = getFloatAttr(shapeElem, "radius");
878                 rigidShape.setShapeType(RigidShapeType.SPHERE);
879                 rigidShape.setRadius(radius);
880             }
881             if(hasChild(rigidElem, "rigidShapeBox")){
882                 Element shapeElem =
883                         getChild(rigidElem, "rigidShapeBox");
884                 float width  = getFloatAttr(shapeElem, "width");
885                 float height = getFloatAttr(shapeElem, "height");
886                 float depth  = getFloatAttr(shapeElem, "depth");
887                 rigidShape.setShapeType(RigidShapeType.BOX);
888                 rigidShape.setWidth(width);
889                 rigidShape.setHeight(height);
890                 rigidShape.setDepth(depth);
891             }
892             if(hasChild(rigidElem, "rigidShapeCapsule")){
893                 Element shapeElem =
894                         getChild(rigidElem, "rigidShapeCapsule");
895                 float height = getFloatAttr(shapeElem, "height");
896                 float radius = getFloatAttr(shapeElem, "radius");
897                 rigidShape.setShapeType(RigidShapeType.CAPSULE);
898                 rigidShape.setHeight(height);
899                 rigidShape.setRadius(radius);
900             }
901
902             float xVal;
903             float yVal;
904             float zVal;
905
906             Element positionElem = getChild(rigidElem, "position");
907             xVal = getFloatAttr(positionElem, "x");
908             yVal = getFloatAttr(positionElem, "y");
909             zVal = getFloatAttr(positionElem, "z");
910             MkPos3D position = rigid.getPosition();
911             position.setXpos(xVal);
912             position.setYpos(yVal);
913             position.setZpos(zVal);
914
915             Element radRotationElem = getChild(rigidElem, "radRotation");
916             xVal = getFloatAttr(radRotationElem, "xRad");
917             yVal = getFloatAttr(radRotationElem, "yRad");
918             zVal = getFloatAttr(radRotationElem, "zRad");
919             Rad3d rotation = rigid.getRotation();
920             rotation.setXRad(xVal);
921             rotation.setYRad(yVal);
922             rotation.setZRad(zVal);
923
924             Element dynamicsElem = getChild(rigidElem, "dynamics");
925             float mass = getFloatAttr(dynamicsElem, "mass");
926             float dampingPosition =
927                     getFloatAttr(dynamicsElem, "dampingPosition");
928             float dampingRotation =
929                     getFloatAttr(dynamicsElem, "dampingRotation");
930             float restitution = getFloatAttr(dynamicsElem, "restitution");
931             float friction = getFloatAttr(dynamicsElem, "friction");
932             DynamicsInfo dynamics = rigid.getDynamicsInfo();
933             dynamics.setMass(mass);
934             dynamics.setDampingPosition(dampingPosition);
935             dynamics.setDampingRotation(dampingRotation);
936             dynamics.setRestitution(restitution);
937             dynamics.setFriction(friction);
938         }
939
940         ListUtil.assignIndexedSerial(rigidList);
941
942         return;
943     }
944
945     /**
946      * DOMから剛体グループリスト情報を組み立てる。
947      * @param pmdModelElem ルート要素
948      * @throws TogaXmlException 構文エラー
949      */
950     private void buildRigidGroupList(Element pmdModelElem)
951             throws TogaXmlException{
952         Element rigidGroupListElem =
953                 getChild(pmdModelElem, "rigidGroupList");
954
955         List<RigidGroup> groupList = this.model.getRigidGroupList();
956
957         for(Element rigidGroupElem
958                 : eachChild(rigidGroupListElem, "rigidGroup")){
959             RigidGroup rigidGroup = new RigidGroup();
960             groupList.add(rigidGroup);
961
962             String rigidGroupId =
963                     getStringAttr(rigidGroupElem, "rigidGroupId");
964             this.rigidGroupMap.put(rigidGroupId, rigidGroup);
965
966             for(Element memberElem
967                     : eachChild(rigidGroupElem, "rigidGroupMember")){
968                 String rigidIdRef = getStringAttr(memberElem, "rigidIdRef");
969                 RigidInfo rigid = this.rigidMap.get(rigidIdRef);
970                 rigidGroup.getRigidList().add(rigid);
971                 rigid.setRigidGroup(rigidGroup);
972             }
973         }
974
975         while(groupList.size() < 16){
976             RigidGroup rigidGroup = new RigidGroup();
977             groupList.add(rigidGroup);
978         }
979
980         ListUtil.assignIndexedSerial(groupList);
981
982         return;
983     }
984
985     /**
986      * DOM内の剛体衝突情報を解決する。
987      * @param pmdModelElem ルート要素
988      * @throws TogaXmlException 構文エラー
989      */
990     private void resolveThroughRigidGroup(Element pmdModelElem)
991             throws TogaXmlException{
992         Element rigidListElem =
993                 getChild(pmdModelElem, "rigidList");
994
995         List<RigidInfo> rigidList = this.model.getRigidList();
996
997         Iterator<RigidInfo> rit = rigidList.iterator();
998         for(Element rigidElem : eachChild(rigidListElem, "rigid")){
999             RigidInfo rigid = rit.next();
1000             for(Element groupElem
1001                     : eachChild(rigidElem, "throughRigidGroup")){
1002                 String groupId = getStringAttr(groupElem, "rigidGroupIdRef");
1003                 RigidGroup group = this.rigidGroupMap.get(groupId);
1004                 rigid.getThroughGroupColl().add(group);
1005             }
1006         }
1007
1008         return;
1009     }
1010
1011     /**
1012      * DOMからジョイントリストを組み立てる。
1013      * @param pmdModelElem ルート要素
1014      * @throws TogaXmlException 構文エラー
1015      */
1016     private void buildJointList(Element pmdModelElem)
1017             throws TogaXmlException{
1018         Element jointListElem =
1019                 getChild(pmdModelElem, "jointList");
1020
1021         List<JointInfo> jointList = this.model.getJointList();
1022
1023         for(Element jointElem : eachChild(jointListElem, "joint")){
1024             JointInfo joint = new JointInfo();
1025             jointList.add(joint);
1026
1027             I18nText name = joint.getJointName();
1028             buildI18nName(jointElem, name);
1029
1030             Element rigidPairElem = getChild(jointElem, "jointedRigidPair");
1031             String rigidIdRef1 = getStringAttr(rigidPairElem, "rigidIdRef1");
1032             String rigidIdRef2 = getStringAttr(rigidPairElem, "rigidIdRef2");
1033             RigidInfo rigid1 = this.rigidMap.get(rigidIdRef1);
1034             RigidInfo rigid2 = this.rigidMap.get(rigidIdRef2);
1035             joint.setRigidPair(rigid1, rigid2);
1036
1037             float xVal;
1038             float yVal;
1039             float zVal;
1040             float xFrom;
1041             float xTo;
1042             float yFrom;
1043             float yTo;
1044             float zFrom;
1045             float zTo;
1046
1047             MkPos3D position = joint.getPosition();
1048             Element positionElem = getChild(jointElem, "position");
1049             xVal = getFloatAttr(positionElem, "x");
1050             yVal = getFloatAttr(positionElem, "y");
1051             zVal = getFloatAttr(positionElem, "z");
1052             position.setXpos(xVal);
1053             position.setYpos(yVal);
1054             position.setZpos(zVal);
1055
1056             TripletRange limitPosition = joint.getPositionRange();
1057             Element limitPositionElem = getChild(jointElem, "limitPosition");
1058             xFrom = getFloatAttr(limitPositionElem, "xFrom");
1059             xTo   = getFloatAttr(limitPositionElem, "xTo");
1060             yFrom = getFloatAttr(limitPositionElem, "yFrom");
1061             yTo   = getFloatAttr(limitPositionElem, "yTo");
1062             zFrom = getFloatAttr(limitPositionElem, "zFrom");
1063             zTo   = getFloatAttr(limitPositionElem, "zTo");
1064             limitPosition.setXRange(xFrom, xTo);
1065             limitPosition.setYRange(yFrom, yTo);
1066             limitPosition.setZRange(zFrom, zTo);
1067
1068             Rad3d rotation = joint.getRotation();
1069             Element rotationElem = getChild(jointElem, "radRotation");
1070             xVal = getFloatAttr(rotationElem, "xRad");
1071             yVal = getFloatAttr(rotationElem, "yRad");
1072             zVal = getFloatAttr(rotationElem, "zRad");
1073             rotation.setXRad(xVal);
1074             rotation.setYRad(yVal);
1075             rotation.setZRad(zVal);
1076
1077             TripletRange limitRotation = joint.getRotationRange();
1078             Element limitRotationElem = getChild(jointElem, "limitRotation");
1079             xFrom = getFloatAttr(limitRotationElem, "xFrom");
1080             xTo   = getFloatAttr(limitRotationElem, "xTo");
1081             yFrom = getFloatAttr(limitRotationElem, "yFrom");
1082             yTo   = getFloatAttr(limitRotationElem, "yTo");
1083             zFrom = getFloatAttr(limitRotationElem, "zFrom");
1084             zTo   = getFloatAttr(limitRotationElem, "zTo");
1085             limitRotation.setXRange(xFrom, xTo);
1086             limitRotation.setYRange(yFrom, yTo);
1087             limitRotation.setZRange(zFrom, zTo);
1088
1089             MkPos3D elasticPosition = joint.getElasticPosition();
1090             Element elasticPositionElem =
1091                     getChild(jointElem, "elasticPosition");
1092             xVal = getFloatAttr(elasticPositionElem, "x");
1093             yVal = getFloatAttr(elasticPositionElem, "y");
1094             zVal = getFloatAttr(elasticPositionElem, "z");
1095             elasticPosition.setXpos(xVal);
1096             elasticPosition.setYpos(yVal);
1097             elasticPosition.setZpos(zVal);
1098
1099             Deg3d elasticRotation = joint.getElasticRotation();
1100             Element elasticRotationElem =
1101                     getChild(jointElem, "elasticRotation");
1102             xVal = getFloatAttr(elasticRotationElem, "xDeg");
1103             yVal = getFloatAttr(elasticRotationElem, "yDeg");
1104             zVal = getFloatAttr(elasticRotationElem, "zDeg");
1105             elasticRotation.setXDeg(xVal);
1106             elasticRotation.setYDeg(yVal);
1107             elasticRotation.setZDeg(zVal);
1108         }
1109
1110         return;
1111     }
1112
1113 }