4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sourceforge.mikutoga.vmd.model.xml;
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;
28 * XML形式でのモーションファイルを読み込む。
30 public class Xml2VmdLoader {
32 private static final String ERRMSG_INVROOT =
33 "RootElem:[{0}] must be [vmdMotion]";
36 private final DocumentBuilder builder;
43 public Xml2VmdLoader(DocumentBuilder builder){
45 assert builder.isNamespaceAware();
46 this.builder = builder;
53 * @param document XMLドキュメント
55 * @throws TogaXmlException 不正なルート要素の検出
57 private static Element getRootElem(Document document)
58 throws TogaXmlException {
59 Element vmdMotionElem = document.getDocumentElement();
60 if( ! Xml.hasNsLocalNameElem(vmdMotionElem, "vmdMotion") ){
62 MessageFormat.format(ERRMSG_INVROOT,
63 vmdMotionElem.getLocalName() );
64 throw new TogaXmlException(message);
71 * @param vmdMotionElem vmdMotion要素
72 * @param vmdMotion モーション
73 * @throws TogaXmlException 構文エラー
75 private static void buildModelName(Element vmdMotionElem,
77 throws TogaXmlException{
78 Element modelNameElem = Xml.getChild(vmdMotionElem, "modelName");
79 String modelName = Xml.getStringAttr(modelNameElem, "name");
80 vmdMotion.setModelName(modelName);
86 * @param vmdMotionElem vmdMotion要素
87 * @param vmdMotion モーション
88 * @throws TogaXmlException 構文エラー
90 private static void buildBoneSeq(Element vmdMotionElem,
92 throws TogaXmlException{
93 NamedListMap<BoneMotion> boneMap = vmdMotion.getBonePartMap();
96 Xml.getChild(vmdMotionElem, "boneMotionSequence");
98 for(Element bonePartElem : Xml.eachChild(boneSeqElem, "bonePart")){
99 buildBonePart(bonePartElem, boneMap);
107 * @param bonePartElem bonePart要素
108 * @param boneMap 名前マップ
109 * @throws TogaXmlException 構文エラー
111 private static void buildBonePart(Element bonePartElem,
112 NamedListMap<BoneMotion> boneMap )
113 throws TogaXmlException{
114 String boneName = Xml.getStringAttr(bonePartElem, "name");
116 for(Element boneMotionElem :
117 Xml.eachChild(bonePartElem, "boneMotion")){
118 BoneMotion boneMotion = buildBoneMotion(boneMotionElem);
119 boneMotion.setBoneName(boneName);
120 boneMap.addNamedElement(boneName, boneMotion);
128 * @param boneMotionElem boneMotion要素
130 * @throws TogaXmlException 構文エラー
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);
138 buildBonePosition(boneMotionElem, boneMotion);
139 if(Xml.pickChild(boneMotionElem, "boneRotQuat") != null){
140 buildBoneRotQuat(boneMotionElem, boneMotion);
142 buildBoneRotEyxz(boneMotionElem, boneMotion);
150 * @param boneMotionElem boneMotion要素
151 * @param boneMotion ボーンモーション
152 * @throws TogaXmlException 構文エラー
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;
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);
169 PosCurve curve = boneMotion.getPosCurve();
170 Xml.buildPosCurve(bonePositionElem, curve);
176 * ボーン回転をクォータニオン形式で読み込む。
177 * @param boneMotionElem boneMotion要素
178 * @param boneMotion ボーンモーション
179 * @throws TogaXmlException 構文エラー
181 private static void buildBoneRotQuat(Element boneMotionElem,
182 BoneMotion boneMotion )
183 throws TogaXmlException{
184 Element boneRotationElem =
185 Xml.getChild(boneMotionElem, "boneRotQuat");
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");
198 BezierParam rotationCurve = boneMotion.getIntpltRotation();
199 Xml.buildCurve(boneRotationElem, rotationCurve);
206 * @param boneMotionElem boneMotion要素
207 * @param boneMotion ボーンモーション
208 * @throws TogaXmlException 構文エラー
210 private static void buildBoneRotEyxz(Element boneMotionElem,
211 BoneMotion boneMotion )
212 throws TogaXmlException{
213 Element boneRotationElem =
214 Xml.getChild(boneMotionElem, "boneRotEyxz");
216 MkQuat rotation = boneMotion.getRotation();
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);
226 BezierParam rotationCurve = boneMotion.getIntpltRotation();
227 Xml.buildCurve(boneRotationElem, rotationCurve);
234 * @param vmdMotionElem vmdMotion要素
235 * @param vmdMotion モーション
236 * @throws TogaXmlException 構文エラー
238 private static void buildMorphSeq(Element vmdMotionElem,
239 VmdMotion vmdMotion )
240 throws TogaXmlException{
241 NamedListMap<MorphMotion> morphMap = vmdMotion.getMorphPartMap();
243 Element morphSeqElem = Xml.getChild(vmdMotionElem, "morphSequence");
245 for(Element morphPartElem :
246 Xml.eachChild(morphSeqElem, "morphPart")){
247 buildMorphPart(morphPartElem, morphMap);
255 * @param morphPartElem morphPart要素
256 * @param morphMap 名前マップ
257 * @throws TogaXmlException 構文エラー
259 private static void buildMorphPart(Element morphPartElem,
260 NamedListMap<MorphMotion> morphMap )
261 throws TogaXmlException{
262 String morphName = Xml.getStringAttr(morphPartElem, "name");
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);
277 * @param morphMotionElem morphMotion要素
279 * @throws TogaXmlException 構文エラー
281 private static MorphMotion buildMorphMotion(Element morphMotionElem)
282 throws TogaXmlException {
283 MorphMotion morphMotion = new MorphMotion();
285 int frameNo = Xml.getIntegerAttr(morphMotionElem, "frame");
286 float flex = Xml.getFloatAttr(morphMotionElem, "flex");
288 morphMotion.setFrameNumber(frameNo);
289 morphMotion.setFlex(flex);
296 * @param source XML入力
298 * @throws SAXException 構文エラー
299 * @throws IOException 入力エラー
300 * @throws TogaXmlException 構文エラー
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();
310 if(Xml.pickChild(vmdMotionElem, "modelName") != null){
311 buildModelName(vmdMotionElem, vmdMotion);
312 buildBoneSeq(vmdMotionElem, vmdMotion);
313 buildMorphSeq(vmdMotionElem, vmdMotion);
315 XmlCameraLoader.buildCameraSeq(vmdMotionElem, vmdMotion);
316 XmlLightingLoader.buildLuminousSeq(vmdMotionElem, vmdMotion);
317 XmlLightingLoader.buildShadowSeq(vmdMotionElem, vmdMotion);