OSDN Git Service

vmdパッケージ導入
[mikutoga/TogaGem.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().put("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>").ln(2);
138
139         ind().putBlockComment(TOP_COMMENT).ln(2);
140
141         ind().put("<vmdMotion").ln();
142         pushNest();
143         ind().putAttr("xmlns", VmdXmlResources.NS_VMDXML).ln();
144         ind().putAttr("xmlns:" + XSINS, XmlResourceResolver.NS_XSD).ln();
145
146         ind().put(XSINS).put(":schemaLocation=").put('"');
147         put(VmdXmlResources.NS_VMDXML).ln();
148         ind().sp(2).put(VmdXmlResources.SCHEMAURI_VMDXML).put('"').ln();
149
150         ind().putAttr("version", VmdXmlResources.VER_VMDXML).ln();
151         popNest();
152         put(">").ln(2);
153
154         if(this.generator != null && this.generator.length() > 0){
155             ind().put("<meta ");
156             putAttr("name", "generator").put(' ');
157             putAttr("content", this.generator);
158             put(" />").ln(2);
159         }
160
161         if(vmdMotion.isModelMotion()){
162             putModelName(vmdMotion);
163             putBoneMotionSequence(vmdMotion);
164             putMorphSequence(vmdMotion);
165         }else{
166             putCameraSequence(vmdMotion);
167             putLuminousSequence(vmdMotion);
168             putShadowSequence(vmdMotion);
169         }
170
171         ind().put("</vmdMotion>").ln(2);
172         ind().put("<!-- EOF -->").ln();
173
174         return;
175     }
176
177     /**
178      * 位置移動補間カーブを出力する。
179      * @param posCurve 移動補間情報
180      * @throws IOException 出力エラー
181      */
182     private void putPositionCurve(PosCurve posCurve)
183             throws IOException{
184         BezierParam xCurve = posCurve.getIntpltXpos();
185         BezierParam yCurve = posCurve.getIntpltYpos();
186         BezierParam zCurve = posCurve.getIntpltZpos();
187
188         ind().putLineComment("X-Y-Z interpolation *3").ln();
189
190         ind();
191         putBezierCurve(xCurve);
192         ln();
193
194         ind();
195         putBezierCurve(yCurve);
196         ln();
197
198         ind();
199         putBezierCurve(zCurve);
200         ln();
201
202         return;
203     }
204
205     /**
206      * ベジェ曲線による補間曲線情報を出力する。
207      * @param bezier ベジェ曲線
208      * @throws IOException 出力エラー
209      */
210     private void putBezierCurve(BezierParam bezier)
211             throws IOException{
212         if(bezier.isDefaultLinear()){
213             put("<defLinear />");
214         }else if(bezier.isDefaultEaseInOut()){
215             put("<defEaseInOut />");
216         }else{
217             put("<bezier ");
218             putIntAttr("p1x", bezier.getP1x()).sp();
219             putIntAttr("p1y", bezier.getP1y()).sp();
220             putIntAttr("p2x", bezier.getP2x()).sp();
221             putIntAttr("p2y", bezier.getP2y()).sp();
222             put("/>");
223         }
224         return;
225     }
226
227     /**
228      * モデル名を出力する。
229      * @param vmdMotion モーションデータ
230      * @throws IOException 出力エラー
231      */
232     private void putModelName(VmdMotion vmdMotion)
233             throws IOException{
234         String modelName = vmdMotion.getModelName();
235
236         ind().putLineComment(modelName).ln();
237         ind().put("<modelName ");
238         putAttr("name", modelName).sp();
239         put("/>").ln(2);
240
241         return;
242     }
243
244     /**
245      * ボーンモーションデータを出力する。
246      * @param vmdMotion モーションデータ
247      * @throws IOException 出力エラー
248      */
249     private void putBoneMotionSequence(VmdMotion vmdMotion)
250             throws IOException{
251         ind().putBlockComment(QUATERNION_COMMENT);
252         ind().putBlockComment(BEZIER_COMMENT);
253
254         ind().put("<boneMotionSequence>").ln();
255
256         pushNest();
257         NamedListMap<BoneMotion> listmap = vmdMotion.getBonePartMap();
258         if( ! listmap.isEmpty() ) ln();
259         for(String boneName : listmap.getNames()){
260             List<BoneMotion> list = listmap.getNamedList(boneName);
261             putBonePart(boneName, list);
262         }
263         popNest();
264
265         ind().put("</boneMotionSequence>").ln(2);
266
267         return;
268     }
269
270     /**
271      * ボーン別モーションデータを出力する。
272      * @param boneName ボーン名
273      * @param list ボーンモーションのリスト
274      * @throws IOException 出力エラー
275      */
276     private void putBonePart(String boneName, List<BoneMotion> list)
277             throws IOException{
278         ind().putLineComment(boneName);
279         String globalName = TypicalBone.primary2global(boneName);
280         if(globalName != null){
281             sp(2).putLineComment("Perhaps : [" + globalName + "]");
282         }
283         ln();
284
285         ind().put("<bonePart ");
286         putAttr("name", boneName).sp();
287         put(">").ln(2);
288
289         pushNest();
290         for(BoneMotion bone : list){
291             putBoneMotion(bone);
292         }
293         popNest();
294
295         ind().put("</bonePart>").ln(2);
296
297         return;
298     }
299
300     /**
301      * ボーンモーションを出力する。
302      * @param boneMotion ボーンモーション
303      * @throws IOException 出力エラー
304      */
305     private void putBoneMotion(BoneMotion boneMotion)
306             throws IOException{
307         ind().put("<boneMotion ");
308         int frameNo = boneMotion.getFrameNumber();
309         putIntAttr("frame", frameNo).sp();
310         put(">").ln();
311
312         pushNest();
313         putBonePosition(boneMotion);
314         if(this.isQuaternionMode){
315             putBoneRotQuat(boneMotion);
316         }else{
317             putBoneRotEyxz(boneMotion);
318         }
319         popNest();
320
321         ind().put("</boneMotion>").ln(2);
322
323         return;
324     }
325
326     /**
327      * ボーン位置を出力する。
328      * @param boneMotion ボーンモーション
329      * @throws IOException 出力エラー
330      */
331     private void putBonePosition(BoneMotion boneMotion)
332             throws IOException{
333         if(boneMotion.hasImplicitPosition()){
334             return;
335         }
336
337         ind().put("<bonePosition ");
338         MkPos3D position = boneMotion.getPosition();
339         float xPos = (float) position.getXpos();
340         float yPos = (float) position.getYpos();
341         float zPos = (float) position.getZpos();
342         putFloatAttr("xPos", xPos).sp();
343         putFloatAttr("yPos", yPos).sp();
344         putFloatAttr("zPos", zPos).sp();
345
346         PosCurve posCurve = boneMotion.getPosCurve();
347         if(posCurve.isDefaultLinear()){
348             put("/>").ln();
349         }else{
350             put(">").ln();
351
352             pushNest();
353             putPositionCurve(posCurve);
354             popNest();
355
356             ind().put("</bonePosition>").ln();
357         }
358
359         return;
360     }
361
362     /**
363      * ボーン回転を出力する。
364      * @param boneMotion ボーンモーション
365      * @throws IOException 出力エラー
366      */
367     private void putBoneRotQuat(BoneMotion boneMotion)
368             throws IOException{
369         MkQuat rotation = boneMotion.getRotation();
370         BezierParam rotCurve = boneMotion.getIntpltRotation();
371
372         ind().put("<boneRotQuat").ln();
373         pushNest();
374         ind().putFloatAttr("qx", (float) rotation.getQ1()).ln();
375         ind().putFloatAttr("qy", (float) rotation.getQ2()).ln();
376         ind().putFloatAttr("qz", (float) rotation.getQ3()).ln();
377         ind().putFloatAttr("qw", (float) rotation.getQW()).ln();
378         popNest();
379         ind();
380
381         if(rotCurve.isDefaultLinear()){
382             put("/>").ln();
383         }else{
384             put(">").ln();
385             pushNest();
386             ind();
387             putBezierCurve(rotCurve);
388             ln();
389             popNest();
390             ind().put("</boneRotQuat>").ln();
391         }
392
393         return;
394     }
395
396     /**
397      * ボーン回転を出力する。
398      * @param boneMotion ボーンモーション
399      * @throws IOException 出力エラー
400      */
401     private void putBoneRotEyxz(BoneMotion boneMotion)
402             throws IOException{
403         MkQuat rotation = boneMotion.getRotation();
404         BezierParam rotCurve = boneMotion.getIntpltRotation();
405
406         EulerYXZ euler = new EulerYXZ();
407         rotation.toEulerYXZ(euler);
408         float xDeg = (float)StrictMath.toDegrees(euler.getXRot());
409         float yDeg = (float)StrictMath.toDegrees(euler.getYRot());
410         float zDeg = (float)StrictMath.toDegrees(euler.getZRot());
411
412         ind().put("<boneRotEyxz").ln();
413         pushNest();
414         ind().putFloatAttr("xDeg", xDeg).ln();
415         ind().putFloatAttr("yDeg", yDeg).ln();
416         ind().putFloatAttr("zDeg", zDeg).ln();
417         popNest();
418         ind();
419
420         if(rotCurve.isDefaultLinear()){
421             put("/>").ln();
422         }else{
423             put(">").ln();
424             pushNest();
425             ind();
426             putBezierCurve(rotCurve);
427             ln();
428             popNest();
429             ind().put("</boneRotEyxz>").ln();
430         }
431
432         return;
433     }
434
435     /**
436      * モーフデータを出力する。
437      * @param vmdMotion モーションデータ
438      * @throws IOException 出力エラー
439      */
440     private void putMorphSequence(VmdMotion vmdMotion)
441             throws IOException{
442         ind().put("<morphSequence>").ln();
443
444         pushNest();
445         NamedListMap<MorphMotion> listmap = vmdMotion.getMorphPartMap();
446         if( ! listmap.isEmpty() ) ln();
447         putMorphPartList(listmap);
448         popNest();
449
450         ind().put("</morphSequence>").ln(2);
451
452         return;
453     }
454
455     /**
456      * 箇所別モーフデータを出力する。
457      * @param listmap モーフデータの名前付きリストマップ
458      * @throws IOException 出力エラー
459      */
460     private void putMorphPartList(NamedListMap<MorphMotion> listmap)
461             throws IOException{
462         for(String morphName : listmap.getNames()){
463             if(VmdConst.isBaseMorphName(morphName)) continue;
464
465             ind().putLineComment(morphName);
466             String globalName = TypicalMorph.primary2global(morphName);
467             if(globalName != null){
468                 sp(2).putLineComment("Perhaps : [" + globalName + "]");
469             }
470             ln();
471
472             ind().put("<morphPart ");
473             putAttr("name", morphName).sp();
474             put(">").ln();
475
476             pushNest();
477             List<MorphMotion> list = listmap.getNamedList(morphName);
478             for(MorphMotion morph : list){
479                 putMorphMotion(morph);
480             }
481             popNest();
482
483             ind().put("</morphPart>").ln(2);
484         }
485
486         return;
487     }
488
489     /**
490      * 個別のモーフモーションを出力する。
491      * @param morphMotion モーフモーション
492      * @throws IOException 出力エラー
493      */
494     private void putMorphMotion(MorphMotion morphMotion)
495             throws IOException{
496         ind().put("<morphMotion ");
497
498         int frameNo = morphMotion.getFrameNumber();
499         float flex = morphMotion.getFlex();
500
501         putIntAttr("frame", frameNo).sp();
502         putFloatAttr("flex", flex).sp();
503
504         put("/>").ln();
505
506         return;
507     }
508
509     /**
510      * カメラ演出データを出力する。
511      * @param vmdMotion 演出データ
512      * @throws IOException 出力エラー
513      */
514     private void putCameraSequence(VmdMotion vmdMotion)
515             throws IOException{
516         ind().putBlockComment(BEZIER_COMMENT);
517         ind().putBlockComment(CAMERA_COMMENT);
518
519         ind().put("<cameraSequence>").ln();
520
521         pushNest();
522         List<CameraMotion> list = vmdMotion.getCameraMotionList();
523         if( ! list.isEmpty() ) ln();
524         for(CameraMotion camera : list){
525             putCameraMotion(camera);
526         }
527         popNest();
528
529         ind().put("</cameraSequence>").ln(2);
530
531         return;
532     }
533
534     /**
535      * カメラモーションを出力する。
536      * @param cameraMotion カメラモーション
537      * @throws IOException 出力エラー
538      */
539     private void putCameraMotion(CameraMotion cameraMotion)
540             throws IOException{
541         ind().put("<cameraMotion ");
542         int frameNo = cameraMotion.getFrameNumber();
543         putIntAttr("frame", frameNo).sp();
544         if( ! cameraMotion.hasPerspective() ){
545             putAttr("hasPerspective", "false").sp();
546         }
547         put(">").ln();
548
549         pushNest();
550         putCameraTarget(cameraMotion);
551         putCameraRotation(cameraMotion);
552         putCameraRange(cameraMotion);
553         putProjection(cameraMotion);
554         popNest();
555
556         ind().put("</cameraMotion>").ln(2);
557
558         return;
559     }
560
561     /**
562      * カメラターゲット情報を出力する。
563      * @param cameraMotion カメラモーション
564      * @throws IOException 出力エラー
565      */
566     private void putCameraTarget(CameraMotion cameraMotion)
567             throws IOException{
568         ind().put("<cameraTarget ");
569         MkPos3D position = cameraMotion.getCameraTarget();
570         putFloatAttr("xPos", (float) position.getXpos()).sp();
571         putFloatAttr("yPos", (float) position.getYpos()).sp();
572         putFloatAttr("zPos", (float) position.getZpos()).sp();
573
574         PosCurve posCurve = cameraMotion.getTargetPosCurve();
575         if(posCurve.isDefaultLinear()){
576             put("/>").ln();
577         }else{
578             put(">").ln();
579
580             pushNest();
581             putPositionCurve(posCurve);
582             popNest();
583
584             ind().put("</cameraTarget>").ln();
585         }
586
587         return;
588     }
589
590     /**
591      * カメラ回転情報を出力する。
592      * @param cameraMotion カメラモーション
593      * @throws IOException 出力エラー
594      */
595     private void putCameraRotation(CameraMotion cameraMotion)
596             throws IOException{
597         ind().put("<cameraRotation ");
598         CameraRotation rotation = cameraMotion.getCameraRotation();
599         putFloatAttr("xRad", rotation.getLatitude()).sp();
600         putFloatAttr("yRad", rotation.getLongitude()).sp();
601         putFloatAttr("zRad", rotation.getRoll()).sp();
602
603         BezierParam rotCurve = cameraMotion.getIntpltRotation();
604         if(rotCurve.isDefaultLinear()){
605             put("/>").ln();
606         }else{
607             put(">").ln();
608             pushNest();
609             ind();
610             putBezierCurve(rotCurve);
611             ln();
612             popNest();
613             ind().put("</cameraRotation>").ln();
614         }
615
616         return;
617     }
618
619     /**
620      * カメラ距離情報を出力する。
621      * @param cameraMotion カメラモーション
622      * @throws IOException 出力エラー
623      */
624     private void putCameraRange(CameraMotion cameraMotion)
625             throws IOException{
626         ind().put("<cameraRange ");
627         float range = cameraMotion.getRange();
628         putFloatAttr("range", range).sp();
629
630         BezierParam rangeCurve = cameraMotion.getIntpltRange();
631         if(rangeCurve.isDefaultLinear()){
632             put("/>").ln();
633         }else{
634             put(">").ln();
635             pushNest();
636             ind();
637             putBezierCurve(rangeCurve);
638             ln();
639             popNest();
640             ind().put("</cameraRange>").ln();
641         }
642
643         return;
644     }
645
646     /**
647      * スクリーン投影情報を出力する。
648      * @param cameraMotion カメラモーション
649      * @throws IOException 出力エラー
650      */
651     private void putProjection(CameraMotion cameraMotion)
652             throws IOException{
653         ind().put("<projection ");
654         putIntAttr("vertDeg", cameraMotion.getProjectionAngle()).sp();
655
656         BezierParam projCurve = cameraMotion.getIntpltProjection();
657         if(projCurve.isDefaultLinear()){
658             put("/>").ln();
659         }else{
660             put(">").ln();
661             pushNest();
662             ind();
663             putBezierCurve(projCurve);
664             ln();
665             popNest();
666             ind().put("</projection>").ln();
667         }
668
669         return;
670     }
671
672     /**
673      * 照明演出データを出力する。
674      * @param vmdMotion 演出データ
675      * @throws IOException 出力エラー
676      */
677     private void putLuminousSequence(VmdMotion vmdMotion)
678             throws IOException{
679         ind().put("<luminousSequence>").ln();
680
681         pushNest();
682         List<LuminousMotion> list = vmdMotion.getLuminousMotionList();
683         if( ! list.isEmpty() ) ln();
684         for(LuminousMotion luminous : list){
685             putLuminousMotion(luminous);
686         }
687         popNest();
688
689         ind().put("</luminousSequence>").ln(2);
690
691         return;
692     }
693
694     /**
695      * 照明モーションを出力する。
696      * @param luminousMotion 照明モーション
697      * @throws IOException 出力エラー
698      */
699     private void putLuminousMotion(LuminousMotion luminousMotion)
700             throws IOException{
701         ind().put("<luminousAct ");
702         int frameNo = luminousMotion.getFrameNumber();
703         putIntAttr("frame", frameNo);
704         put(" >").ln();
705
706         LuminousColor color = luminousMotion.getColor();
707         LuminousVector vector = luminousMotion.getDirection();
708
709         pushNest();
710         putLuminousColor(color);
711         putLuminousDirection(vector);
712         popNest();
713
714         ind().put("</luminousAct>").ln(2);
715
716         return;
717     }
718
719     /**
720      * 光源色情報を出力する。
721      * @param color 光源色
722      * @throws IOException 出力エラー
723      */
724     private void putLuminousColor(LuminousColor color)
725             throws IOException{
726         ind().put("<lumiColor ");
727         putFloatAttr("rCol", color.getColR()).sp();
728         putFloatAttr("gCol", color.getColG()).sp();
729         putFloatAttr("bCol", color.getColB()).sp();
730         put("/>").ln();
731
732         return;
733     }
734
735     /**
736      * 照明方向情報を出力する。
737      * @param vector 照明方向
738      * @throws IOException 出力エラー
739      */
740     private void putLuminousDirection(LuminousVector vector)
741             throws IOException{
742         ind().put("<lumiDirection ");
743         putFloatAttr("xVec", vector.getVecX()).sp();
744         putFloatAttr("yVec", vector.getVecY()).sp();
745         putFloatAttr("zVec", vector.getVecZ()).sp();
746         put("/>").ln();
747
748         return;
749     }
750
751     /**
752      * シャドウ演出データを出力する。
753      * @param vmdMotion 演出データ
754      * @throws IOException 出力エラー
755      */
756     private void putShadowSequence(VmdMotion vmdMotion)
757             throws IOException{
758         ind().putBlockComment(SHADOW_COMMENT);
759
760         ind().put("<shadowSequence>").ln();
761
762         pushNest();
763         List<ShadowMotion> list = vmdMotion.getShadowMotionList();
764         for(ShadowMotion shadow : list){
765             putShadowMotion(shadow);
766         }
767         popNest();
768
769         ind().put("</shadowSequence>").ln(2);
770
771         return;
772     }
773
774     /**
775      * シャドウモーションを出力する。
776      * @param shadowMotion シャドウモーション
777      * @throws IOException 出力エラー
778      */
779     private void putShadowMotion(ShadowMotion shadowMotion)
780             throws IOException{
781         ind().put("<shadowAct ");
782
783         int frameNo = shadowMotion.getFrameNumber();
784         ShadowMode mode = shadowMotion.getShadowMode();
785         float rawParam = shadowMotion.getRawScopeParam();
786
787         putIntAttr("frame", frameNo).sp();
788         putAttr("mode", mode.name()).sp();
789         putFloatAttr("rawParam", rawParam).sp();
790
791         put("/>");
792
793         double uiVal = ShadowMotion.rawParamToScope(rawParam);
794         long lVal = Math.round(uiVal);
795         sp().putLineComment("UI:" + lVal).ln();
796
797         return;
798     }
799
800 }