OSDN Git Service

vmdパッケージ導入
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / vmd / model / xml / Xml2VmdLoader.java
1 /*
2  * xml loader
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 MikuToga Partners
6  */
7
8 package jp.sourceforge.mikutoga.vmd.model.xml;
9
10 import java.io.IOException;
11 import java.text.MessageFormat;
12 import javax.xml.parsers.DocumentBuilder;
13 import jp.sourceforge.mikutoga.math.MkPos3D;
14 import jp.sourceforge.mikutoga.math.MkQuat;
15 import jp.sourceforge.mikutoga.vmd.model.BezierParam;
16 import jp.sourceforge.mikutoga.vmd.model.BoneMotion;
17 import jp.sourceforge.mikutoga.vmd.model.MorphMotion;
18 import jp.sourceforge.mikutoga.vmd.model.NamedListMap;
19 import jp.sourceforge.mikutoga.vmd.model.PosCurve;
20 import jp.sourceforge.mikutoga.vmd.model.VmdMotion;
21 import jp.sourceforge.mikutoga.xml.TogaXmlException;
22 import org.w3c.dom.Document;
23 import org.w3c.dom.Element;
24 import org.xml.sax.InputSource;
25 import org.xml.sax.SAXException;
26
27 /**
28  * XML形式でのモーションファイルを読み込む。
29  */
30 public class Xml2VmdLoader {
31
32     private static final String ERRMSG_INVROOT =
33             "RootElem:[{0}] must be [vmdMotion]";
34
35
36     private final DocumentBuilder builder;
37
38
39     /**
40      * コンストラクタ。
41      * @param builder ビルダ
42      */
43     public Xml2VmdLoader(DocumentBuilder builder){
44         super();
45         assert builder.isNamespaceAware();
46         this.builder = builder;
47         return;
48     }
49
50
51     /**
52      * ルート要素の取得とチェックを行う。
53      * @param document XMLドキュメント
54      * @return ルート要素
55      * @throws TogaXmlException 不正なルート要素の検出
56      */
57     private static Element getRootElem(Document document)
58             throws TogaXmlException {
59         Element vmdMotionElem = document.getDocumentElement();
60         if( ! Xml.hasNsLocalNameElem(vmdMotionElem, "vmdMotion") ){
61             String message =
62                     MessageFormat.format(ERRMSG_INVROOT,
63                                          vmdMotionElem.getLocalName() );
64             throw new TogaXmlException(message);
65         }
66         return vmdMotionElem;
67     }
68
69     /**
70      * モーションのモデル名を読み込む。
71      * @param vmdMotionElem vmdMotion要素
72      * @param vmdMotion モーション
73      * @throws TogaXmlException 構文エラー
74      */
75     private static void buildModelName(Element vmdMotionElem,
76                                        VmdMotion vmdMotion)
77             throws TogaXmlException{
78         Element modelNameElem = Xml.getChild(vmdMotionElem, "modelName");
79         String modelName = Xml.getStringAttr(modelNameElem, "name");
80         vmdMotion.setModelName(modelName);
81         return;
82     }
83
84     /**
85      * ボーンシーケンスを読み込む。
86      * @param vmdMotionElem vmdMotion要素
87      * @param vmdMotion モーション
88      * @throws TogaXmlException 構文エラー
89      */
90     private static void buildBoneSeq(Element vmdMotionElem,
91                                      VmdMotion vmdMotion )
92             throws TogaXmlException{
93         NamedListMap<BoneMotion> boneMap = vmdMotion.getBonePartMap();
94
95         Element boneSeqElem =
96                 Xml.getChild(vmdMotionElem, "boneMotionSequence");
97
98         for(Element bonePartElem : Xml.eachChild(boneSeqElem, "bonePart")){
99             buildBonePart(bonePartElem, boneMap);
100         }
101
102         return;
103     }
104
105     /**
106      * ボーンパートを読み込む。
107      * @param bonePartElem bonePart要素
108      * @param boneMap 名前マップ
109      * @throws TogaXmlException 構文エラー
110      */
111     private static void buildBonePart(Element bonePartElem,
112                                       NamedListMap<BoneMotion> boneMap )
113             throws TogaXmlException{
114         String boneName = Xml.getStringAttr(bonePartElem, "name");
115
116         for(Element boneMotionElem :
117                 Xml.eachChild(bonePartElem, "boneMotion")){
118             BoneMotion boneMotion = buildBoneMotion(boneMotionElem);
119             boneMotion.setBoneName(boneName);
120             boneMap.addNamedElement(boneName, boneMotion);
121         }
122
123         return;
124     }
125
126     /**
127      * ボーンモーションを読み込む。
128      * @param boneMotionElem boneMotion要素
129      * @return ボーンモーション
130      * @throws TogaXmlException 構文エラー
131      */
132     private static BoneMotion buildBoneMotion(Element boneMotionElem)
133             throws TogaXmlException {
134         BoneMotion boneMotion = new BoneMotion();
135         int frameNo = Xml.getIntegerAttr(boneMotionElem, "frame");
136         boneMotion.setFrameNumber(frameNo);
137
138         buildBonePosition(boneMotionElem, boneMotion);
139         if(Xml.pickChild(boneMotionElem, "boneRotQuat") != null){
140             buildBoneRotQuat(boneMotionElem, boneMotion);
141         }else{
142             buildBoneRotEyxz(boneMotionElem, boneMotion);
143         }
144
145         return boneMotion;
146     }
147
148     /**
149      * ボーン位置を読み込む。
150      * @param boneMotionElem boneMotion要素
151      * @param boneMotion ボーンモーション
152      * @throws TogaXmlException 構文エラー
153      */
154     private static void buildBonePosition(Element boneMotionElem,
155                                           BoneMotion boneMotion )
156             throws TogaXmlException {
157         Element bonePositionElem =
158                 Xml.pickChild(boneMotionElem, "bonePosition");
159         if(bonePositionElem == null) return;
160
161         MkPos3D position = boneMotion.getPosition();
162         float xPos = Xml.getFloatAttr(bonePositionElem, "xPos");
163         float yPos = Xml.getFloatAttr(bonePositionElem, "yPos");
164         float zPos = Xml.getFloatAttr(bonePositionElem, "zPos");
165         position.setXpos(xPos);
166         position.setYpos(yPos);
167         position.setZpos(zPos);
168
169         PosCurve curve = boneMotion.getPosCurve();
170         Xml.buildPosCurve(bonePositionElem, curve);
171
172         return;
173     }
174
175     /**
176      * ボーン回転をクォータニオン形式で読み込む。
177      * @param boneMotionElem boneMotion要素
178      * @param boneMotion ボーンモーション
179      * @throws TogaXmlException 構文エラー
180      */
181     private static void buildBoneRotQuat(Element boneMotionElem,
182                                           BoneMotion boneMotion )
183             throws TogaXmlException{
184         Element boneRotationElem =
185                 Xml.getChild(boneMotionElem, "boneRotQuat");
186
187         MkQuat rotation = boneMotion.getRotation();
188         float qx = Xml.getFloatAttr(boneRotationElem, "qx");
189         float qy = Xml.getFloatAttr(boneRotationElem, "qy");
190         float qz = Xml.getFloatAttr(boneRotationElem, "qz");
191         float qw = Xml.getFloatAttr(boneRotationElem, "qw");
192
193         rotation.setQ1(qx);
194         rotation.setQ2(qy);
195         rotation.setQ3(qz);
196         rotation.setQW(qw);
197
198         BezierParam rotationCurve = boneMotion.getIntpltRotation();
199         Xml.buildCurve(boneRotationElem, rotationCurve);
200
201         return;
202     }
203
204     /**
205      * ボーン回転をオイラー角で読み込む。
206      * @param boneMotionElem boneMotion要素
207      * @param boneMotion ボーンモーション
208      * @throws TogaXmlException 構文エラー
209      */
210     private static void buildBoneRotEyxz(Element boneMotionElem,
211                                          BoneMotion boneMotion )
212             throws TogaXmlException{
213         Element boneRotationElem =
214                 Xml.getChild(boneMotionElem, "boneRotEyxz");
215
216         MkQuat rotation = boneMotion.getRotation();
217
218         float xDeg = Xml.getFloatAttr(boneRotationElem, "xDeg");
219         float yDeg = Xml.getFloatAttr(boneRotationElem, "yDeg");
220         float zDeg = Xml.getFloatAttr(boneRotationElem, "zDeg");
221         float xRad = (float)StrictMath.toRadians(xDeg);
222         float yRad = (float)StrictMath.toRadians(yDeg);
223         float zRad = (float)StrictMath.toRadians(zDeg);
224         rotation.readEulerYXZ(xRad, yRad, zRad);
225
226         BezierParam rotationCurve = boneMotion.getIntpltRotation();
227         Xml.buildCurve(boneRotationElem, rotationCurve);
228
229         return;
230     }
231
232     /**
233      * モーフシーケンスを読み込む。
234      * @param vmdMotionElem vmdMotion要素
235      * @param vmdMotion モーション
236      * @throws TogaXmlException 構文エラー
237      */
238     private static void buildMorphSeq(Element vmdMotionElem,
239                                       VmdMotion vmdMotion )
240             throws TogaXmlException{
241         NamedListMap<MorphMotion> morphMap = vmdMotion.getMorphPartMap();
242
243         Element morphSeqElem = Xml.getChild(vmdMotionElem, "morphSequence");
244
245         for(Element morphPartElem :
246                 Xml.eachChild(morphSeqElem, "morphPart")){
247             buildMorphPart(morphPartElem, morphMap);
248         }
249
250         return;
251     }
252
253     /**
254      * モーフパートを読み込む。
255      * @param morphPartElem morphPart要素
256      * @param morphMap 名前マップ
257      * @throws TogaXmlException 構文エラー
258      */
259     private static void buildMorphPart(Element morphPartElem,
260                                        NamedListMap<MorphMotion> morphMap )
261             throws TogaXmlException{
262         String morphName = Xml.getStringAttr(morphPartElem, "name");
263
264         Iterable<Element> childs =
265                 Xml.eachChild(morphPartElem, "morphMotion");
266         for(Element morphMotionElem : childs){
267             MorphMotion morphMotion = buildMorphMotion(morphMotionElem);
268             morphMotion.setMorphName(morphName);
269             morphMap.addNamedElement(morphName, morphMotion);
270         }
271
272         return;
273     }
274
275     /**
276      * モーフモーションを読み込む。
277      * @param morphMotionElem morphMotion要素
278      * @return モーフモーション
279      * @throws TogaXmlException 構文エラー
280      */
281     private static MorphMotion buildMorphMotion(Element morphMotionElem)
282             throws TogaXmlException {
283         MorphMotion morphMotion = new MorphMotion();
284
285         int frameNo = Xml.getIntegerAttr(morphMotionElem, "frame");
286         float flex = Xml.getFloatAttr(morphMotionElem, "flex");
287
288         morphMotion.setFrameNumber(frameNo);
289         morphMotion.setFlex(flex);
290
291         return morphMotion;
292     }
293
294     /**
295      * XMLのパースを開始する。
296      * @param source XML入力
297      * @return モーションデータ
298      * @throws SAXException 構文エラー
299      * @throws IOException 入力エラー
300      * @throws TogaXmlException 構文エラー
301      */
302     public VmdMotion parse(InputSource source)
303             throws SAXException, IOException, TogaXmlException{
304         Document document = this.builder.parse(source);
305         Element vmdMotionElem = getRootElem(document);
306         VmdMotion vmdMotion = new VmdMotion();
307
308         // ignore <meta>
309
310         if(Xml.pickChild(vmdMotionElem, "modelName") != null){
311             buildModelName(vmdMotionElem, vmdMotion);
312             buildBoneSeq(vmdMotionElem, vmdMotion);
313             buildMorphSeq(vmdMotionElem, vmdMotion);
314         }else{
315             XmlCameraLoader.buildCameraSeq(vmdMotionElem, vmdMotion);
316             XmlLightingLoader.buildLuminousSeq(vmdMotionElem, vmdMotion);
317             XmlLightingLoader.buildShadowSeq(vmdMotionElem, vmdMotion);
318         }
319
320         return vmdMotion;
321     }
322
323 }