OSDN Git Service

SAXパーサ対応
[mikutoga/Vmd2XML.git] / src / main / java / jp / sfjp / mikutoga / vmd / model / binio / BasicExporter.java
1 /*
2  * bone motion & morph exporter
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.vmd.model.binio;
9
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.nio.ByteBuffer;
13 import java.nio.charset.Charset;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Map;
17 import jp.sfjp.mikutoga.bin.export.BinaryExporter;
18 import jp.sfjp.mikutoga.bin.export.IllegalTextExportException;
19 import jp.sfjp.mikutoga.math.MkPos3D;
20 import jp.sfjp.mikutoga.math.MkQuat;
21 import jp.sfjp.mikutoga.vmd.VmdConst;
22 import jp.sfjp.mikutoga.vmd.VmdUniq;
23 import jp.sfjp.mikutoga.vmd.model.BezierParam;
24 import jp.sfjp.mikutoga.vmd.model.BoneMotion;
25 import jp.sfjp.mikutoga.vmd.model.MorphMotion;
26 import jp.sfjp.mikutoga.vmd.model.PosCurve;
27 import jp.sfjp.mikutoga.vmd.model.VmdMotion;
28
29 /**
30  * ボーンモーション及びモーフ情報のエクスポーター。
31  */
32 class BasicExporter extends BinaryExporter {
33
34     private static final int BZ_SIZE = 4;           // 4byte Bezier parameter
35     private static final int BZXYZR_SIZE = BZ_SIZE * 4; // XYZR Bezier
36     private static final int BZ_REDUNDANT = 4;          // redundant spare
37     private static final int BZTOTAL_SIZE = BZXYZR_SIZE * BZ_REDUNDANT;
38
39     private static final Charset CS_ASCII = Charset.forName("US-ASCII");
40
41     // '\0' * 5byte の版もあり
42     private static final String HEADFILLER = "\u0000" + "JKLM";
43
44     private static final byte[] FDFILLER =
45         { (byte)0x00, (byte)0xfd };
46     private static final  byte[] INTPLT_FILLER = {
47         (byte) 0x01,  // 0x00の版もあり。
48         (byte) 0x00,
49         (byte) 0x00,
50     };
51
52
53     private final byte[] motionIntplt = new byte[BZTOTAL_SIZE];
54     private final ByteBuffer intpltBuf;
55     private final ByteBuffer rdBuf;
56
57
58     /**
59      * コンストラクタ。
60      * @param stream 出力ストリーム
61      */
62     BasicExporter(OutputStream stream){
63         super(stream);
64
65         this.intpltBuf = ByteBuffer.wrap(this.motionIntplt);
66         ByteBuffer buf = ByteBuffer.wrap(this.motionIntplt, 0, BZXYZR_SIZE);
67         this.rdBuf = buf.asReadOnlyBuffer();
68
69         return;
70     }
71
72
73     /**
74      * ヘッダ情報を出力する。
75      * @throws IOException 出力エラー
76      */
77     void dumpHeader() throws IOException{
78         byte[] header = (VmdConst.MAGIC_TXT + HEADFILLER).getBytes(CS_ASCII);
79         assert header.length == VmdConst.HEADER_LENGTH;
80
81         dumpByteArray(header);
82
83         return;
84     }
85
86     /**
87      * モデル名を出力する。
88      * <p>演出データのモデル名には
89      * 便宜的に
90      * {@link jp.sfjp.mikutoga.vmd.VmdUniq#MODELNAME_STAGEACT}
91      * が使われる。
92      * @param motion モーションデータ
93      * @throws IOException 出力エラー
94      * @throws IllegalTextExportException 不正なモデル名の出現
95      */
96     void dumpModelName(VmdMotion motion)
97             throws IOException, IllegalTextExportException{
98         String modelName = motion.getModelName();
99         if(modelName == null) modelName = VmdUniq.MODELNAME_STAGEACT;
100
101         dumpFixedW31j(modelName, VmdConst.MODELNAME_MAX, FDFILLER);
102
103         return;
104     }
105
106     /**
107      * ボーンモーション情報を出力する。
108      * @param motion モーションデータ
109      * @throws IOException 出力エラー
110      * @throws IllegalTextExportException 不正なボーン名の出現
111      */
112     void dumpBoneMotion(VmdMotion motion)
113             throws IOException, IllegalTextExportException{
114         Map<String, List<BoneMotion>> map = motion.getBonePartMap();
115
116         List<BoneMotion> bmotionList = new LinkedList<BoneMotion>();
117         for(List<BoneMotion> eachList : map.values()){
118             bmotionList.addAll(eachList);
119         }
120         dumpLeInt(bmotionList.size());
121
122         for(BoneMotion boneMotion : bmotionList){
123             String boneName = boneMotion.getBoneName();
124             dumpFixedW31j(boneName, VmdConst.BONENAME_MAX, FDFILLER);
125
126             int frame = boneMotion.getFrameNumber();
127             dumpLeInt(frame);
128
129             MkPos3D position = boneMotion.getPosition();
130             dumpBonePosition(position);
131
132             MkQuat rotation = boneMotion.getRotation();
133             dumpBoneRotation(rotation);
134
135             dumpBoneInterpolation(boneMotion);
136         }
137
138         return;
139     }
140
141     /**
142      * ボーン位置情報を出力する。
143      * @param position ボーン位置情報
144      * @throws IOException 出力エラー
145      */
146     private void dumpBonePosition(MkPos3D position)
147             throws IOException{
148         float xPos = (float) position.getXpos();
149         float yPos = (float) position.getYpos();
150         float zPos = (float) position.getZpos();
151
152         dumpLeFloat(xPos);
153         dumpLeFloat(yPos);
154         dumpLeFloat(zPos);
155
156         return;
157     }
158
159     /**
160      * ボーン回転情報を出力する。
161      * @param rotation ボーン回転情報
162      * @throws IOException 出力エラー
163      */
164     private void dumpBoneRotation(MkQuat rotation)
165             throws IOException{
166         float qx = (float) rotation.getQ1();
167         float qy = (float) rotation.getQ2();
168         float qz = (float) rotation.getQ3();
169         float qw = (float) rotation.getQW();
170
171         dumpLeFloat(qx);
172         dumpLeFloat(qy);
173         dumpLeFloat(qz);
174         dumpLeFloat(qw);
175
176         return;
177     }
178
179     /**
180      * ボーンモーションの補間情報を出力する。
181      * @param boneMotion ボーンモーション
182      * @throws IOException 出力エラー
183      */
184     private void dumpBoneInterpolation(BoneMotion boneMotion)
185             throws IOException{
186         PosCurve posCurve = boneMotion.getPosCurve();
187         BezierParam xCurve = posCurve.getIntpltXpos();
188         BezierParam yCurve = posCurve.getIntpltYpos();
189         BezierParam zCurve = posCurve.getIntpltZpos();
190         BezierParam rCurve = boneMotion.getIntpltRotation();
191
192         this.intpltBuf.clear();
193
194         this.intpltBuf.put(xCurve.getP1x());
195         this.intpltBuf.put(yCurve.getP1x());
196         this.intpltBuf.put(zCurve.getP1x());
197         this.intpltBuf.put(rCurve.getP1x());
198
199         this.intpltBuf.put(xCurve.getP1y());
200         this.intpltBuf.put(yCurve.getP1y());
201         this.intpltBuf.put(zCurve.getP1y());
202         this.intpltBuf.put(rCurve.getP1y());
203
204         this.intpltBuf.put(xCurve.getP2x());
205         this.intpltBuf.put(yCurve.getP2x());
206         this.intpltBuf.put(zCurve.getP2x());
207         this.intpltBuf.put(rCurve.getP2x());
208
209         this.intpltBuf.put(xCurve.getP2y());
210         this.intpltBuf.put(yCurve.getP2y());
211         this.intpltBuf.put(zCurve.getP2y());
212         this.intpltBuf.put(rCurve.getP2y());
213
214         assert this.intpltBuf.position() == BZXYZR_SIZE;
215
216         redundantCopy();
217
218         dumpByteArray(this.motionIntplt);
219
220         return;
221     }
222
223     /**
224      * 補間情報冗長部の組み立て。
225      * <p>※ MMDの版によって若干出力内容が異なる。
226      */
227     private void redundantCopy(){
228         this.intpltBuf.position(BZXYZR_SIZE);
229
230         for(int lack = 1; lack < BZ_REDUNDANT; lack++){
231             this.rdBuf.position(lack);
232             this.intpltBuf.put(this.rdBuf);
233             this.intpltBuf.put(INTPLT_FILLER, 0, lack);
234         }
235
236         assert this.intpltBuf.position() == BZTOTAL_SIZE;
237
238         return;
239     }
240
241     /**
242      * モーフ情報を出力する。
243      * @param motion モーションデータ
244      * @throws IOException 出力エラー
245      * @throws IllegalTextExportException 不正なモーフ名の出現
246      */
247     void dumpMorphMotion(VmdMotion motion)
248             throws IOException, IllegalTextExportException{
249         Map<String, List<MorphMotion>> map = motion.getMorphPartMap();
250
251         List<MorphMotion> morphList = new LinkedList<MorphMotion>();
252         for(List<MorphMotion> eachList : map.values()){
253             morphList.addAll(eachList);
254         }
255         dumpLeInt(morphList.size());
256
257         for(MorphMotion morphMotion : morphList){
258             String morphName = morphMotion.getMorphName();
259             dumpFixedW31j(morphName, VmdConst.MORPHNAME_MAX, FDFILLER);
260
261             int frame = morphMotion.getFrameNumber();
262             dumpLeInt(frame);
263
264             float flex = morphMotion.getFlex();
265             dumpLeFloat(flex);
266         }
267
268         return;
269     }
270
271 }