OSDN Git Service

TogaGem対応
[mikutoga/Vmd2XML.git] / src / main / java / jp / sourceforge / mikutoga / vmd / model / xml / VmdXmlExporter.java
1 /*
2  * vmd-xml exporter
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.io.OutputStream;
12 import java.util.List;
13 import jp.sourceforge.mikutoga.math.EulerYXZ;
14 import jp.sourceforge.mikutoga.math.MkPos3D;
15 import jp.sourceforge.mikutoga.math.MkQuat;
16 import jp.sourceforge.mikutoga.typical.TypicalBone;
17 import jp.sourceforge.mikutoga.typical.TypicalMorph;
18 import jp.sourceforge.mikutoga.vmd.IllegalVmdDataException;
19 import jp.sourceforge.mikutoga.vmd.VmdConst;
20 import jp.sourceforge.mikutoga.vmd.model.BezierParam;
21 import jp.sourceforge.mikutoga.vmd.model.BoneMotion;
22 import jp.sourceforge.mikutoga.vmd.model.CameraMotion;
23 import jp.sourceforge.mikutoga.vmd.model.CameraRotation;
24 import jp.sourceforge.mikutoga.vmd.model.LuminousColor;
25 import jp.sourceforge.mikutoga.vmd.model.LuminousMotion;
26 import jp.sourceforge.mikutoga.vmd.model.LuminousVector;
27 import jp.sourceforge.mikutoga.vmd.model.MorphMotion;
28 import jp.sourceforge.mikutoga.vmd.model.NamedListMap;
29 import jp.sourceforge.mikutoga.vmd.model.PosCurve;
30 import jp.sourceforge.mikutoga.vmd.model.ShadowMode;
31 import jp.sourceforge.mikutoga.vmd.model.ShadowMotion;
32 import jp.sourceforge.mikutoga.vmd.model.VmdMotion;
33 import jp.sourceforge.mikutoga.xml.BasicXmlExporter;
34 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
35
36 /**
37  * VMDモーションデータをXMLへエクスポートする。
38  */
39 public class VmdXmlExporter extends BasicXmlExporter {
40
41     private static final String XSINS = "xsi";
42
43     private static final String TOP_COMMENT =
44             "  MikuMikuDance\n    motion-data(*.vmd) on XML";
45
46     private static final String QUATERNION_COMMENT =
47           "  bone-rotation has Quaternion parameters [boneRotQuat]\n"
48         + "  or YXZ-Euler angles [boneRotEyxz].\n"
49         + "  Quaternion is strongly recommended"
50         +   " if you are data-exchanging.";
51
52     private static final String BEZIER_COMMENT =
53           "  motion interpolation is defined by Bezier-cubic-curve.\n"
54         + "  implicit bezier curve point : P0=(0,0) P3=(127,127)\n"
55         + "  defLinear : MMD default linear curve."
56         + " P1=(20,20) P2=(107,107) [DEFAULT]\n"
57         + "  defEaseInOut : MMD default ease-in-out curve."
58         + " P1=(64,0) P2=(64,127)";
59
60     private static final String CAMERA_COMMENT =
61           "  camera-rotation has polar-coordinates parameters.\n"
62         + "  xRad = -radian(UI_X) [latitude]\n"
63         + "  yRad =  radian(UI_Y) [longitude]\n"
64         + "  zRad =  radian(UI_Z) [roll]\n"
65         + "  range = -(UI_RANGE)";
66
67     private static final String SHADOW_COMMENT =
68              "  UI_VALUE = EFFECTIVE_RANGE * 100 ???\n"
69             +"  rawParam = 0.1 - (UI_VALUE / 1.0E+5)\n\n"
70             +"  NONE   : no self-shadow\n"
71             +"  MODE_1 : reduce shadow-quality suddenly at range\n"
72             +"  MODE_2 : reduce shadow-quality gradually with range";
73
74
75     private boolean isQuaternionMode = true;
76     private String generator = "";
77
78
79     /**
80      * コンストラクタ。
81      * 文字エンコーディングはUTF-8が用いられる。
82      * @param stream 出力ストリーム
83      */
84     public VmdXmlExporter(OutputStream stream){
85         super(stream);
86         return;
87     }
88
89
90     /**
91      * ボーン回転量をクォータニオンで出力するか否か設定する。
92      * <p>デフォルトではtrue
93      * @param mode trueだとクォータニオン、falseだとオイラー角で出力される。
94      */
95     public void setQuaternionMode(boolean mode){
96         this.isQuaternionMode = mode;
97     }
98
99     /**
100      * Generatorメタ情報を設定する。
101      * @param generatorArg Generatorメタ情報
102      * @throws NullPointerException 引数がnull
103      */
104     public void setGenerator(String generatorArg)
105             throws NullPointerException{
106         if(generatorArg == null) throw new NullPointerException();
107         this.generator = generatorArg;
108         return;
109     }
110
111     /**
112      * VMDモーションデータをXML形式で出力する。
113      * <p>モーションデータと演出データで振り分けられる。
114      * @param vmdMotion VMDモーションデータ
115      * @throws IOException 出力エラー
116      * @throws IllegalVmdDataException 不正なモーションデータを検出
117      */
118     public void putVmdXml(VmdMotion vmdMotion)
119             throws IOException, IllegalVmdDataException{
120         try{
121             putVmdXmlImpl(vmdMotion);
122         }finally{
123             flush();
124         }
125         return;
126     }
127
128     /**
129      * VMDモーションデータをXML形式で出力する。
130      * <p>モーションデータと演出データで振り分けられる。
131      * @param vmdMotion VMDモーションデータ
132      * @throws IOException 出力エラー
133      * @throws IllegalVmdDataException 不正なモーションデータを検出
134      */
135     private void putVmdXmlImpl(VmdMotion vmdMotion)
136             throws IOException, IllegalVmdDataException{
137         ind().putRawText("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>")
138              .ln(2);
139
140         ind().putBlockComment(TOP_COMMENT).ln(2);
141
142         ind().putRawText("<vmdMotion").ln();
143         pushNest();
144         ind().putAttr("xmlns", VmdXmlResources.NS_VMDXML).ln();
145         ind().putAttr("xmlns:" + XSINS, XmlResourceResolver.NS_XSD).ln();
146
147         ind().putRawText(XSINS).putRawText(":schemaLocation=")
148              .putRawCh('"');
149         putRawText(VmdXmlResources.NS_VMDXML).ln();
150         ind().sp(2).putRawText(VmdXmlResources.SCHEMAURI_VMDXML)
151              .putRawCh('"')
152              .ln();
153
154         ind().putAttr("version", VmdXmlResources.VER_VMDXML).ln();
155         popNest();
156         putRawText(">").ln(2);
157
158         if(this.generator != null && this.generator.length() > 0){
159             ind().putRawText("<meta ");
160             putAttr("name", "generator").putRawCh(' ');
161             putAttr("content", this.generator);
162             putRawText(" />").ln(2);
163         }
164
165         if(vmdMotion.isModelMotion()){
166             putModelName(vmdMotion);
167             putBoneMotionSequence(vmdMotion);
168             putMorphSequence(vmdMotion);
169         }else{
170             putCameraSequence(vmdMotion);
171             putLuminousSequence(vmdMotion);
172             putShadowSequence(vmdMotion);
173         }
174
175         ind().putRawText("</vmdMotion>").ln(2);
176         ind().putRawText("<!-- EOF -->").ln();
177
178         return;
179     }
180
181     /**
182      * 位置移動補間カーブを出力する。
183      * @param posCurve 移動補間情報
184      * @throws IOException 出力エラー
185      */
186     private void putPositionCurve(PosCurve posCurve)
187             throws IOException{
188         BezierParam xCurve = posCurve.getIntpltXpos();
189         BezierParam yCurve = posCurve.getIntpltYpos();
190         BezierParam zCurve = posCurve.getIntpltZpos();
191
192         ind().putLineComment("X-Y-Z interpolation *3").ln();
193
194         ind();
195         putBezierCurve(xCurve);
196         ln();
197
198         ind();
199         putBezierCurve(yCurve);
200         ln();
201
202         ind();
203         putBezierCurve(zCurve);
204         ln();
205
206         return;
207     }
208
209     /**
210      * ベジェ曲線による補間曲線情報を出力する。
211      * @param bezier ベジェ曲線
212      * @throws IOException 出力エラー
213      */
214     private void putBezierCurve(BezierParam bezier)
215             throws IOException{
216         if(bezier.isDefaultLinear()){
217             putRawText("<defLinear />");
218         }else if(bezier.isDefaultEaseInOut()){
219             putRawText("<defEaseInOut />");
220         }else{
221             putRawText("<bezier ");
222             putIntAttr("p1x", bezier.getP1x()).sp();
223             putIntAttr("p1y", bezier.getP1y()).sp();
224             putIntAttr("p2x", bezier.getP2x()).sp();
225             putIntAttr("p2y", bezier.getP2y()).sp();
226             putRawText("/>");
227         }
228         return;
229     }
230
231     /**
232      * モデル名を出力する。
233      * @param vmdMotion モーションデータ
234      * @throws IOException 出力エラー
235      */
236     private void putModelName(VmdMotion vmdMotion)
237             throws IOException{
238         String modelName = vmdMotion.getModelName();
239
240         ind().putLineComment(modelName).ln();
241         ind().putRawText("<modelName ");
242         putAttr("name", modelName).sp();
243         putRawText("/>").ln(2);
244
245         return;
246     }
247
248     /**
249      * ボーンモーションデータを出力する。
250      * @param vmdMotion モーションデータ
251      * @throws IOException 出力エラー
252      */
253     private void putBoneMotionSequence(VmdMotion vmdMotion)
254             throws IOException{
255         ind().putBlockComment(QUATERNION_COMMENT);
256         ind().putBlockComment(BEZIER_COMMENT);
257
258         ind().putRawText("<boneMotionSequence>").ln();
259
260         pushNest();
261         NamedListMap<BoneMotion> listmap = vmdMotion.getBonePartMap();
262         if( ! listmap.isEmpty() ) ln();
263         for(String boneName : listmap.getNames()){
264             List<BoneMotion> list = listmap.getNamedList(boneName);
265             putBonePart(boneName, list);
266         }
267         popNest();
268
269         ind().putRawText("</boneMotionSequence>").ln(2);
270
271         return;
272     }
273
274     /**
275      * ボーン別モーションデータを出力する。
276      * @param boneName ボーン名
277      * @param list ボーンモーションのリスト
278      * @throws IOException 出力エラー
279      */
280     private void putBonePart(String boneName, List<BoneMotion> list)
281             throws IOException{
282         ind().putLineComment(boneName);
283         String globalName = TypicalBone.primary2global(boneName);
284         if(globalName != null){
285             sp(2).putLineComment("Perhaps : [" + globalName + "]");
286         }
287         ln();
288
289         ind().putRawText("<bonePart ");
290         putAttr("name", boneName).sp();
291         putRawText(">").ln(2);
292
293         pushNest();
294         for(BoneMotion bone : list){
295             putBoneMotion(bone);
296         }
297         popNest();
298
299         ind().putRawText("</bonePart>").ln(2);
300
301         return;
302     }
303
304     /**
305      * ボーンモーションを出力する。
306      * @param boneMotion ボーンモーション
307      * @throws IOException 出力エラー
308      */
309     private void putBoneMotion(BoneMotion boneMotion)
310             throws IOException{
311         ind().putRawText("<boneMotion ");
312         int frameNo = boneMotion.getFrameNumber();
313         putIntAttr("frame", frameNo).sp();
314         putRawText(">").ln();
315
316         pushNest();
317         putBonePosition(boneMotion);
318         if(this.isQuaternionMode){
319             putBoneRotQuat(boneMotion);
320         }else{
321             putBoneRotEyxz(boneMotion);
322         }
323         popNest();
324
325         ind().putRawText("</boneMotion>").ln(2);
326
327         return;
328     }
329
330     /**
331      * ボーン位置を出力する。
332      * @param boneMotion ボーンモーション
333      * @throws IOException 出力エラー
334      */
335     private void putBonePosition(BoneMotion boneMotion)
336             throws IOException{
337         if(boneMotion.hasImplicitPosition()){
338             return;
339         }
340
341         ind().putRawText("<bonePosition ");
342         MkPos3D position = boneMotion.getPosition();
343         float xPos = (float) position.getXpos();
344         float yPos = (float) position.getYpos();
345         float zPos = (float) position.getZpos();
346         putFloatAttr("xPos", xPos).sp();
347         putFloatAttr("yPos", yPos).sp();
348         putFloatAttr("zPos", zPos).sp();
349
350         PosCurve posCurve = boneMotion.getPosCurve();
351         if(posCurve.isDefaultLinear()){
352             putRawText("/>").ln();
353         }else{
354             putRawText(">").ln();
355
356             pushNest();
357             putPositionCurve(posCurve);
358             popNest();
359
360             ind().putRawText("</bonePosition>").ln();
361         }
362
363         return;
364     }
365
366     /**
367      * ボーン回転を出力する。
368      * @param boneMotion ボーンモーション
369      * @throws IOException 出力エラー
370      */
371     private void putBoneRotQuat(BoneMotion boneMotion)
372             throws IOException{
373         MkQuat rotation = boneMotion.getRotation();
374         BezierParam rotCurve = boneMotion.getIntpltRotation();
375
376         ind().putRawText("<boneRotQuat").ln();
377         pushNest();
378         ind().putFloatAttr("qx", (float) rotation.getQ1()).ln();
379         ind().putFloatAttr("qy", (float) rotation.getQ2()).ln();
380         ind().putFloatAttr("qz", (float) rotation.getQ3()).ln();
381         ind().putFloatAttr("qw", (float) rotation.getQW()).ln();
382         popNest();
383         ind();
384
385         if(rotCurve.isDefaultLinear()){
386             putRawText("/>").ln();
387         }else{
388             putRawText(">").ln();
389             pushNest();
390             ind();
391             putBezierCurve(rotCurve);
392             ln();
393             popNest();
394             ind().putRawText("</boneRotQuat>").ln();
395         }
396
397         return;
398     }
399
400     /**
401      * ボーン回転を出力する。
402      * @param boneMotion ボーンモーション
403      * @throws IOException 出力エラー
404      */
405     private void putBoneRotEyxz(BoneMotion boneMotion)
406             throws IOException{
407         MkQuat rotation = boneMotion.getRotation();
408         BezierParam rotCurve = boneMotion.getIntpltRotation();
409
410         EulerYXZ euler = new EulerYXZ();
411         rotation.toEulerYXZ(euler);
412         float xDeg = (float)StrictMath.toDegrees(euler.getXRot());
413         float yDeg = (float)StrictMath.toDegrees(euler.getYRot());
414         float zDeg = (float)StrictMath.toDegrees(euler.getZRot());
415
416         ind().putRawText("<boneRotEyxz").ln();
417         pushNest();
418         ind().putFloatAttr("xDeg", xDeg).ln();
419         ind().putFloatAttr("yDeg", yDeg).ln();
420         ind().putFloatAttr("zDeg", zDeg).ln();
421         popNest();
422         ind();
423
424         if(rotCurve.isDefaultLinear()){
425             putRawText("/>").ln();
426         }else{
427             putRawText(">").ln();
428             pushNest();
429             ind();
430             putBezierCurve(rotCurve);
431             ln();
432             popNest();
433             ind().putRawText("</boneRotEyxz>").ln();
434         }
435
436         return;
437     }
438
439     /**
440      * モーフデータを出力する。
441      * @param vmdMotion モーションデータ
442      * @throws IOException 出力エラー
443      */
444     private void putMorphSequence(VmdMotion vmdMotion)
445             throws IOException{
446         ind().putRawText("<morphSequence>").ln();
447
448         pushNest();
449         NamedListMap<MorphMotion> listmap = vmdMotion.getMorphPartMap();
450         if( ! listmap.isEmpty() ) ln();
451         putMorphPartList(listmap);
452         popNest();
453
454         ind().putRawText("</morphSequence>").ln(2);
455
456         return;
457     }
458
459     /**
460      * 箇所別モーフデータを出力する。
461      * @param listmap モーフデータの名前付きリストマップ
462      * @throws IOException 出力エラー
463      */
464     private void putMorphPartList(NamedListMap<MorphMotion> listmap)
465             throws IOException{
466         for(String morphName : listmap.getNames()){
467             if(VmdConst.isBaseMorphName(morphName)) continue;
468
469             ind().putLineComment(morphName);
470             String globalName = TypicalMorph.primary2global(morphName);
471             if(globalName != null){
472                 sp(2).putLineComment("Perhaps : [" + globalName + "]");
473             }
474             ln();
475
476             ind().putRawText("<morphPart ");
477             putAttr("name", morphName).sp();
478             putRawText(">").ln();
479
480             pushNest();
481             List<MorphMotion> list = listmap.getNamedList(morphName);
482             for(MorphMotion morph : list){
483                 putMorphMotion(morph);
484             }
485             popNest();
486
487             ind().putRawText("</morphPart>").ln(2);
488         }
489
490         return;
491     }
492
493     /**
494      * 個別のモーフモーションを出力する。
495      * @param morphMotion モーフモーション
496      * @throws IOException 出力エラー
497      */
498     private void putMorphMotion(MorphMotion morphMotion)
499             throws IOException{
500         ind().putRawText("<morphMotion ");
501
502         int frameNo = morphMotion.getFrameNumber();
503         float flex = morphMotion.getFlex();
504
505         putIntAttr("frame", frameNo).sp();
506         putFloatAttr("flex", flex).sp();
507
508         putRawText("/>").ln();
509
510         return;
511     }
512
513     /**
514      * カメラ演出データを出力する。
515      * @param vmdMotion 演出データ
516      * @throws IOException 出力エラー
517      */
518     private void putCameraSequence(VmdMotion vmdMotion)
519             throws IOException{
520         ind().putBlockComment(BEZIER_COMMENT);
521         ind().putBlockComment(CAMERA_COMMENT);
522
523         ind().putRawText("<cameraSequence>").ln();
524
525         pushNest();
526         List<CameraMotion> list = vmdMotion.getCameraMotionList();
527         if( ! list.isEmpty() ) ln();
528         for(CameraMotion camera : list){
529             putCameraMotion(camera);
530         }
531         popNest();
532
533         ind().putRawText("</cameraSequence>").ln(2);
534
535         return;
536     }
537
538     /**
539      * カメラモーションを出力する。
540      * @param cameraMotion カメラモーション
541      * @throws IOException 出力エラー
542      */
543     private void putCameraMotion(CameraMotion cameraMotion)
544             throws IOException{
545         ind().putRawText("<cameraMotion ");
546         int frameNo = cameraMotion.getFrameNumber();
547         putIntAttr("frame", frameNo).sp();
548         if( ! cameraMotion.hasPerspective() ){
549             putAttr("hasPerspective", "false").sp();
550         }
551         putRawText(">").ln();
552
553         pushNest();
554         putCameraTarget(cameraMotion);
555         putCameraRotation(cameraMotion);
556         putCameraRange(cameraMotion);
557         putProjection(cameraMotion);
558         popNest();
559
560         ind().putRawText("</cameraMotion>").ln(2);
561
562         return;
563     }
564
565     /**
566      * カメラターゲット情報を出力する。
567      * @param cameraMotion カメラモーション
568      * @throws IOException 出力エラー
569      */
570     private void putCameraTarget(CameraMotion cameraMotion)
571             throws IOException{
572         ind().putRawText("<cameraTarget ");
573         MkPos3D position = cameraMotion.getCameraTarget();
574         putFloatAttr("xPos", (float) position.getXpos()).sp();
575         putFloatAttr("yPos", (float) position.getYpos()).sp();
576         putFloatAttr("zPos", (float) position.getZpos()).sp();
577
578         PosCurve posCurve = cameraMotion.getTargetPosCurve();
579         if(posCurve.isDefaultLinear()){
580             putRawText("/>").ln();
581         }else{
582             putRawText(">").ln();
583
584             pushNest();
585             putPositionCurve(posCurve);
586             popNest();
587
588             ind().putRawText("</cameraTarget>").ln();
589         }
590
591         return;
592     }
593
594     /**
595      * カメラ回転情報を出力する。
596      * @param cameraMotion カメラモーション
597      * @throws IOException 出力エラー
598      */
599     private void putCameraRotation(CameraMotion cameraMotion)
600             throws IOException{
601         ind().putRawText("<cameraRotation ");
602         CameraRotation rotation = cameraMotion.getCameraRotation();
603         putFloatAttr("xRad", rotation.getLatitude()).sp();
604         putFloatAttr("yRad", rotation.getLongitude()).sp();
605         putFloatAttr("zRad", rotation.getRoll()).sp();
606
607         BezierParam rotCurve = cameraMotion.getIntpltRotation();
608         if(rotCurve.isDefaultLinear()){
609             putRawText("/>").ln();
610         }else{
611             putRawText(">").ln();
612             pushNest();
613             ind();
614             putBezierCurve(rotCurve);
615             ln();
616             popNest();
617             ind().putRawText("</cameraRotation>").ln();
618         }
619
620         return;
621     }
622
623     /**
624      * カメラ距離情報を出力する。
625      * @param cameraMotion カメラモーション
626      * @throws IOException 出力エラー
627      */
628     private void putCameraRange(CameraMotion cameraMotion)
629             throws IOException{
630         ind().putRawText("<cameraRange ");
631         float range = cameraMotion.getRange();
632         putFloatAttr("range", range).sp();
633
634         BezierParam rangeCurve = cameraMotion.getIntpltRange();
635         if(rangeCurve.isDefaultLinear()){
636             putRawText("/>").ln();
637         }else{
638             putRawText(">").ln();
639             pushNest();
640             ind();
641             putBezierCurve(rangeCurve);
642             ln();
643             popNest();
644             ind().putRawText("</cameraRange>").ln();
645         }
646
647         return;
648     }
649
650     /**
651      * スクリーン投影情報を出力する。
652      * @param cameraMotion カメラモーション
653      * @throws IOException 出力エラー
654      */
655     private void putProjection(CameraMotion cameraMotion)
656             throws IOException{
657         ind().putRawText("<projection ");
658         putIntAttr("vertDeg", cameraMotion.getProjectionAngle()).sp();
659
660         BezierParam projCurve = cameraMotion.getIntpltProjection();
661         if(projCurve.isDefaultLinear()){
662             putRawText("/>").ln();
663         }else{
664             putRawText(">").ln();
665             pushNest();
666             ind();
667             putBezierCurve(projCurve);
668             ln();
669             popNest();
670             ind().putRawText("</projection>").ln();
671         }
672
673         return;
674     }
675
676     /**
677      * 照明演出データを出力する。
678      * @param vmdMotion 演出データ
679      * @throws IOException 出力エラー
680      */
681     private void putLuminousSequence(VmdMotion vmdMotion)
682             throws IOException{
683         ind().putRawText("<luminousSequence>").ln();
684
685         pushNest();
686         List<LuminousMotion> list = vmdMotion.getLuminousMotionList();
687         if( ! list.isEmpty() ) ln();
688         for(LuminousMotion luminous : list){
689             putLuminousMotion(luminous);
690         }
691         popNest();
692
693         ind().putRawText("</luminousSequence>").ln(2);
694
695         return;
696     }
697
698     /**
699      * 照明モーションを出力する。
700      * @param luminousMotion 照明モーション
701      * @throws IOException 出力エラー
702      */
703     private void putLuminousMotion(LuminousMotion luminousMotion)
704             throws IOException{
705         ind().putRawText("<luminousAct ");
706         int frameNo = luminousMotion.getFrameNumber();
707         putIntAttr("frame", frameNo);
708         putRawText(" >").ln();
709
710         LuminousColor color = luminousMotion.getColor();
711         LuminousVector vector = luminousMotion.getDirection();
712
713         pushNest();
714         putLuminousColor(color);
715         putLuminousDirection(vector);
716         popNest();
717
718         ind().putRawText("</luminousAct>").ln(2);
719
720         return;
721     }
722
723     /**
724      * 光源色情報を出力する。
725      * @param color 光源色
726      * @throws IOException 出力エラー
727      */
728     private void putLuminousColor(LuminousColor color)
729             throws IOException{
730         ind().putRawText("<lumiColor ");
731         putFloatAttr("rCol", color.getColR()).sp();
732         putFloatAttr("gCol", color.getColG()).sp();
733         putFloatAttr("bCol", color.getColB()).sp();
734         putRawText("/>").ln();
735
736         return;
737     }
738
739     /**
740      * 照明方向情報を出力する。
741      * @param vector 照明方向
742      * @throws IOException 出力エラー
743      */
744     private void putLuminousDirection(LuminousVector vector)
745             throws IOException{
746         ind().putRawText("<lumiDirection ");
747         putFloatAttr("xVec", vector.getVecX()).sp();
748         putFloatAttr("yVec", vector.getVecY()).sp();
749         putFloatAttr("zVec", vector.getVecZ()).sp();
750         putRawText("/>").ln();
751
752         return;
753     }
754
755     /**
756      * シャドウ演出データを出力する。
757      * @param vmdMotion 演出データ
758      * @throws IOException 出力エラー
759      */
760     private void putShadowSequence(VmdMotion vmdMotion)
761             throws IOException{
762         ind().putBlockComment(SHADOW_COMMENT);
763
764         ind().putRawText("<shadowSequence>").ln();
765
766         pushNest();
767         List<ShadowMotion> list = vmdMotion.getShadowMotionList();
768         for(ShadowMotion shadow : list){
769             putShadowMotion(shadow);
770         }
771         popNest();
772
773         ind().putRawText("</shadowSequence>").ln(2);
774
775         return;
776     }
777
778     /**
779      * シャドウモーションを出力する。
780      * @param shadowMotion シャドウモーション
781      * @throws IOException 出力エラー
782      */
783     private void putShadowMotion(ShadowMotion shadowMotion)
784             throws IOException{
785         ind().putRawText("<shadowAct ");
786
787         int frameNo = shadowMotion.getFrameNumber();
788         ShadowMode mode = shadowMotion.getShadowMode();
789         float rawParam = shadowMotion.getRawScopeParam();
790
791         putIntAttr("frame", frameNo).sp();
792         putAttr("mode", mode.name()).sp();
793         putFloatAttr("rawParam", rawParam).sp();
794
795         putRawText("/>");
796
797         double uiVal = ShadowMotion.rawParamToScope(rawParam);
798         long lVal = Math.round(uiVal);
799         sp().putLineComment("UI:" + lVal).ln();
800
801         return;
802     }
803
804 }