2 * bone motion & morph exporter
4 * License : The MIT License
5 * Copyright(c) 2011 MikuToga Partners
8 package jp.sfjp.mikutoga.vmd.model.binio;
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;
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;
30 * ボーンモーション及びモーフ情報のエクスポーター。
32 class BasicExporter extends BinaryExporter {
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;
39 private static final Charset CS_ASCII = Charset.forName("US-ASCII");
42 private static final String HEADFILLER = "\u0000" + "JKLM";
44 private static final byte[] FDFILLER =
45 { (byte)0x00, (byte)0xfd };
46 private static final byte[] INTPLT_FILLER = {
47 (byte) 0x01, // 0x00の版もあり。
53 private final byte[] motionIntplt = new byte[BZTOTAL_SIZE];
54 private final ByteBuffer intpltBuf;
55 private final ByteBuffer rdBuf;
60 * @param stream 出力ストリーム
62 BasicExporter(OutputStream stream){
65 this.intpltBuf = ByteBuffer.wrap(this.motionIntplt);
66 ByteBuffer buf = ByteBuffer.wrap(this.motionIntplt, 0, BZXYZR_SIZE);
67 this.rdBuf = buf.asReadOnlyBuffer();
75 * @throws IOException 出力エラー
77 void dumpHeader() throws IOException{
78 byte[] header = (VmdConst.MAGIC_TXT + HEADFILLER).getBytes(CS_ASCII);
79 assert header.length == VmdConst.HEADER_LENGTH;
81 dumpByteArray(header);
90 * {@link jp.sfjp.mikutoga.vmd.VmdUniq#MODELNAME_STAGEACT}
92 * @param motion モーションデータ
93 * @throws IOException 出力エラー
94 * @throws IllegalTextExportException 不正なモデル名の出現
96 void dumpModelName(VmdMotion motion)
97 throws IOException, IllegalTextExportException{
98 String modelName = motion.getModelName();
99 if(modelName == null) modelName = VmdUniq.MODELNAME_STAGEACT;
101 dumpFixedW31j(modelName, VmdConst.MODELNAME_MAX, FDFILLER);
108 * @param motion モーションデータ
109 * @throws IOException 出力エラー
110 * @throws IllegalTextExportException 不正なボーン名の出現
112 void dumpBoneMotion(VmdMotion motion)
113 throws IOException, IllegalTextExportException{
114 Map<String, List<BoneMotion>> map = motion.getBonePartMap();
116 List<BoneMotion> bmotionList = new LinkedList<BoneMotion>();
117 for(List<BoneMotion> eachList : map.values()){
118 bmotionList.addAll(eachList);
120 dumpLeInt(bmotionList.size());
122 for(BoneMotion boneMotion : bmotionList){
123 String boneName = boneMotion.getBoneName();
124 dumpFixedW31j(boneName, VmdConst.BONENAME_MAX, FDFILLER);
126 int frame = boneMotion.getFrameNumber();
129 MkPos3D position = boneMotion.getPosition();
130 dumpBonePosition(position);
132 MkQuat rotation = boneMotion.getRotation();
133 dumpBoneRotation(rotation);
135 dumpBoneInterpolation(boneMotion);
143 * @param position ボーン位置情報
144 * @throws IOException 出力エラー
146 private void dumpBonePosition(MkPos3D position)
148 float xPos = (float) position.getXpos();
149 float yPos = (float) position.getYpos();
150 float zPos = (float) position.getZpos();
161 * @param rotation ボーン回転情報
162 * @throws IOException 出力エラー
164 private void dumpBoneRotation(MkQuat rotation)
166 float qx = (float) rotation.getQ1();
167 float qy = (float) rotation.getQ2();
168 float qz = (float) rotation.getQ3();
169 float qw = (float) rotation.getQW();
180 * ボーンモーションの補間情報を出力する。
181 * @param boneMotion ボーンモーション
182 * @throws IOException 出力エラー
184 private void dumpBoneInterpolation(BoneMotion boneMotion)
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();
192 this.intpltBuf.clear();
194 this.intpltBuf.put(xCurve.getP1x());
195 this.intpltBuf.put(yCurve.getP1x());
196 this.intpltBuf.put(zCurve.getP1x());
197 this.intpltBuf.put(rCurve.getP1x());
199 this.intpltBuf.put(xCurve.getP1y());
200 this.intpltBuf.put(yCurve.getP1y());
201 this.intpltBuf.put(zCurve.getP1y());
202 this.intpltBuf.put(rCurve.getP1y());
204 this.intpltBuf.put(xCurve.getP2x());
205 this.intpltBuf.put(yCurve.getP2x());
206 this.intpltBuf.put(zCurve.getP2x());
207 this.intpltBuf.put(rCurve.getP2x());
209 this.intpltBuf.put(xCurve.getP2y());
210 this.intpltBuf.put(yCurve.getP2y());
211 this.intpltBuf.put(zCurve.getP2y());
212 this.intpltBuf.put(rCurve.getP2y());
214 assert this.intpltBuf.position() == BZXYZR_SIZE;
218 dumpByteArray(this.motionIntplt);
225 * <p>※ MMDの版によって若干出力内容が異なる。
227 private void redundantCopy(){
228 this.intpltBuf.position(BZXYZR_SIZE);
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);
236 assert this.intpltBuf.position() == BZTOTAL_SIZE;
243 * @param motion モーションデータ
244 * @throws IOException 出力エラー
245 * @throws IllegalTextExportException 不正なモーフ名の出現
247 void dumpMorphMotion(VmdMotion motion)
248 throws IOException, IllegalTextExportException{
249 Map<String, List<MorphMotion>> map = motion.getMorphPartMap();
251 List<MorphMotion> morphList = new LinkedList<MorphMotion>();
252 for(List<MorphMotion> eachList : map.values()){
253 morphList.addAll(eachList);
255 dumpLeInt(morphList.size());
257 for(MorphMotion morphMotion : morphList){
258 String morphName = morphMotion.getMorphName();
259 dumpFixedW31j(morphName, VmdConst.MORPHNAME_MAX, FDFILLER);
261 int frame = morphMotion.getFrameNumber();
264 float flex = morphMotion.getFlex();