OSDN Git Service

Pmd2XMLとの共通化
[mikutoga/Vmd2XML.git] / src / main / java / jp / sfjp / mikutoga / vmd / model / binio / BasicExporter.java
diff --git a/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BasicExporter.java b/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BasicExporter.java
new file mode 100644 (file)
index 0000000..6567d65
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * bone motion & morph exporter
+ *
+ * License : The MIT License
+ * Copyright(c) 2011 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.vmd.model.binio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import jp.sfjp.mikutoga.bin.export.BinaryExporter;
+import jp.sfjp.mikutoga.bin.export.IllegalTextExportException;
+import jp.sfjp.mikutoga.math.MkPos3D;
+import jp.sfjp.mikutoga.math.MkQuat;
+import jp.sfjp.mikutoga.vmd.VmdConst;
+import jp.sfjp.mikutoga.vmd.VmdUniq;
+import jp.sfjp.mikutoga.vmd.model.BezierParam;
+import jp.sfjp.mikutoga.vmd.model.BoneMotion;
+import jp.sfjp.mikutoga.vmd.model.MorphMotion;
+import jp.sfjp.mikutoga.vmd.model.PosCurve;
+import jp.sfjp.mikutoga.vmd.model.VmdMotion;
+
+/**
+ * ボーンモーション及びモーフ情報のエクスポーター。
+ */
+class BasicExporter extends BinaryExporter {
+
+    private static final int BZ_SIZE = 4;           // 4byte Bezier parameter
+    private static final int BZXYZR_SIZE = BZ_SIZE * 4; // XYZR Bezier
+    private static final int BZ_REDUNDANT = 4;          // redundant spare
+    private static final int BZTOTAL_SIZE = BZXYZR_SIZE * BZ_REDUNDANT;
+
+    private static final Charset CS_ASCII = Charset.forName("US-ASCII");
+    private static final String HEADFILLER = "\u0000" + "JKLM";
+    private static final byte[] FDFILLER =
+        { (byte)0x00, (byte)0xfd };
+    private static final  byte[] INTPLT_FILLER = {
+        (byte) 0x01,  // 0x00の版もあり。
+        (byte) 0x00,
+        (byte) 0x00,
+    };
+
+
+    private final byte[] motionIntplt = new byte[BZTOTAL_SIZE];
+    private final ByteBuffer intpltBuf;
+    private final ByteBuffer rdBuf;
+
+
+    /**
+     * コンストラクタ。
+     * @param stream 出力ストリーム
+     */
+    BasicExporter(OutputStream stream){
+        super(stream);
+
+        this.intpltBuf = ByteBuffer.wrap(this.motionIntplt);
+        ByteBuffer buf = ByteBuffer.wrap(this.motionIntplt, 0, BZXYZR_SIZE);
+        this.rdBuf = buf.asReadOnlyBuffer();
+
+        return;
+    }
+
+
+    /**
+     * ヘッダ情報を出力する。
+     * @throws IOException 出力エラー
+     */
+    void dumpHeader() throws IOException{
+        byte[] header = (VmdConst.MAGIC_TXT + HEADFILLER).getBytes(CS_ASCII);
+        assert header.length == VmdConst.HEADER_LENGTH;
+
+        dumpByteArray(header);
+
+        return;
+    }
+
+    /**
+     * モデル名を出力する。
+     * <p>演出データのモデル名には
+     * 便宜的に
+     * {@link jp.sfjp.mikutoga.vmd.VmdUniq#MODELNAME_STAGEACT}
+     * が使われる。
+     * @param motion モーションデータ
+     * @throws IOException 出力エラー
+     * @throws IllegalTextExportException 不正なモデル名の出現
+     */
+    void dumpModelName(VmdMotion motion)
+            throws IOException, IllegalTextExportException{
+        String modelName = motion.getModelName();
+        if(modelName == null) modelName = VmdUniq.MODELNAME_STAGEACT;
+
+        dumpFixedW31j(modelName, VmdConst.MODELNAME_MAX, FDFILLER);
+
+        return;
+    }
+
+    /**
+     * ボーンモーション情報を出力する。
+     * @param motion モーションデータ
+     * @throws IOException 出力エラー
+     * @throws IllegalTextExportException 不正なボーン名の出現
+     */
+    void dumpBoneMotion(VmdMotion motion)
+            throws IOException, IllegalTextExportException{
+        Map<String, List<BoneMotion>> map = motion.getBonePartMap();
+
+        List<BoneMotion> bmotionList = new LinkedList<BoneMotion>();
+        for(List<BoneMotion> eachList : map.values()){
+            bmotionList.addAll(eachList);
+        }
+        dumpLeInt(bmotionList.size());
+
+        for(BoneMotion boneMotion : bmotionList){
+            String boneName = boneMotion.getBoneName();
+            dumpFixedW31j(boneName, VmdConst.BONENAME_MAX, FDFILLER);
+
+            int frame = boneMotion.getFrameNumber();
+            dumpLeInt(frame);
+
+            MkPos3D position = boneMotion.getPosition();
+            dumpBonePosition(position);
+
+            MkQuat rotation = boneMotion.getRotation();
+            dumpBoneRotation(rotation);
+
+            dumpBoneInterpolation(boneMotion);
+        }
+
+        return;
+    }
+
+    /**
+     * ボーン位置情報を出力する。
+     * @param position ボーン位置情報
+     * @throws IOException 出力エラー
+     */
+    private void dumpBonePosition(MkPos3D position)
+            throws IOException{
+        float xPos = (float) position.getXpos();
+        float yPos = (float) position.getYpos();
+        float zPos = (float) position.getZpos();
+
+        dumpLeFloat(xPos);
+        dumpLeFloat(yPos);
+        dumpLeFloat(zPos);
+
+        return;
+    }
+
+    /**
+     * ボーン回転情報を出力する。
+     * @param rotation ボーン回転情報
+     * @throws IOException 出力エラー
+     */
+    private void dumpBoneRotation(MkQuat rotation)
+            throws IOException{
+        float qx = (float) rotation.getQ1();
+        float qy = (float) rotation.getQ2();
+        float qz = (float) rotation.getQ3();
+        float qw = (float) rotation.getQW();
+
+        dumpLeFloat(qx);
+        dumpLeFloat(qy);
+        dumpLeFloat(qz);
+        dumpLeFloat(qw);
+
+        return;
+    }
+
+    /**
+     * ボーンモーションの補間情報を出力する。
+     * @param boneMotion ボーンモーション
+     * @throws IOException 出力エラー
+     */
+    private void dumpBoneInterpolation(BoneMotion boneMotion)
+            throws IOException{
+        PosCurve posCurve = boneMotion.getPosCurve();
+        BezierParam xCurve = posCurve.getIntpltXpos();
+        BezierParam yCurve = posCurve.getIntpltYpos();
+        BezierParam zCurve = posCurve.getIntpltZpos();
+        BezierParam rCurve = boneMotion.getIntpltRotation();
+
+        this.intpltBuf.clear();
+
+        this.intpltBuf.put(xCurve.getP1x());
+        this.intpltBuf.put(yCurve.getP1x());
+        this.intpltBuf.put(zCurve.getP1x());
+        this.intpltBuf.put(rCurve.getP1x());
+
+        this.intpltBuf.put(xCurve.getP1y());
+        this.intpltBuf.put(yCurve.getP1y());
+        this.intpltBuf.put(zCurve.getP1y());
+        this.intpltBuf.put(rCurve.getP1y());
+
+        this.intpltBuf.put(xCurve.getP2x());
+        this.intpltBuf.put(yCurve.getP2x());
+        this.intpltBuf.put(zCurve.getP2x());
+        this.intpltBuf.put(rCurve.getP2x());
+
+        this.intpltBuf.put(xCurve.getP2y());
+        this.intpltBuf.put(yCurve.getP2y());
+        this.intpltBuf.put(zCurve.getP2y());
+        this.intpltBuf.put(rCurve.getP2y());
+
+        assert this.intpltBuf.position() == BZXYZR_SIZE;
+
+        redundantCopy();
+
+        dumpByteArray(this.motionIntplt);
+
+        return;
+    }
+
+    /**
+     * 補間情報冗長部の組み立て。
+     * <p>※ MMDの版によって若干出力内容が異なる。
+     */
+    private void redundantCopy(){
+        this.intpltBuf.position(BZXYZR_SIZE);
+
+        for(int lack = 1; lack < BZ_REDUNDANT; lack++){
+            this.rdBuf.position(lack);
+            this.intpltBuf.put(this.rdBuf);
+            this.intpltBuf.put(INTPLT_FILLER, 0, lack);
+        }
+
+        assert this.intpltBuf.position() == BZTOTAL_SIZE;
+
+        return;
+    }
+
+    /**
+     * モーフ情報を出力する。
+     * @param motion モーションデータ
+     * @throws IOException 出力エラー
+     * @throws IllegalTextExportException 不正なモーフ名の出現
+     */
+    void dumpMorphMotion(VmdMotion motion)
+            throws IOException, IllegalTextExportException{
+        Map<String, List<MorphMotion>> map = motion.getMorphPartMap();
+
+        List<MorphMotion> morphList = new LinkedList<MorphMotion>();
+        for(List<MorphMotion> eachList : map.values()){
+            morphList.addAll(eachList);
+        }
+        dumpLeInt(morphList.size());
+
+        for(MorphMotion morphMotion : morphList){
+            String morphName = morphMotion.getMorphName();
+            dumpFixedW31j(morphName, VmdConst.MORPHNAME_MAX, FDFILLER);
+
+            int frame = morphMotion.getFrameNumber();
+            dumpLeInt(frame);
+
+            float flex = morphMotion.getFlex();
+            dumpLeFloat(flex);
+        }
+
+        return;
+    }
+
+}