OSDN Git Service

MMD Ver7.40 対応 新スキーマ開発開始
authorOlyutorskii <olyutorskii@users.osdn.me>
Sat, 8 Jun 2013 04:30:39 +0000 (13:30 +0900)
committerOlyutorskii <olyutorskii@users.osdn.me>
Sat, 8 Jun 2013 04:30:39 +0000 (13:30 +0900)
20 files changed:
CHANGELOG.txt
pom.xml
src/main/java/jp/sfjp/mikutoga/vmd/model/IkSwitch.java [new file with mode: 0644]
src/main/java/jp/sfjp/mikutoga/vmd/model/NumberedVmdFlag.java [new file with mode: 0644]
src/main/java/jp/sfjp/mikutoga/vmd/model/VmdMotion.java
src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolExporter.java [new file with mode: 0644]
src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolLoader.java [new file with mode: 0644]
src/main/java/jp/sfjp/mikutoga/vmd/model/binio/VmdExporter.java
src/main/java/jp/sfjp/mikutoga/vmd/model/binio/VmdLoader.java
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxAttr.java [moved from src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxXsdUtil.java with 75% similarity]
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxCameraListener.java
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxLightingListener.java
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxMotionListener.java
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/SaxVmdListener.java
src/main/java/jp/sfjp/mikutoga/vmd/model/xml/XmlHandler.java
src/main/java/jp/sfjp/mikutoga/vmd2xml/Vmd2XmlConv.java
src/main/resources/jp/sfjp/mikutoga/vmd/model/xml/resources/vmdxml-130609A.xsd [new file with mode: 0644]
src/test/java/jp/sfjp/mikutoga/vmd/model/VmdMotionTest.java
src/test/resources/testdata/vmd130609/minimum/minmotion.xml [new file with mode: 0644]
src/test/resources/testdata/vmd130609/small/onlyFlag.xml [new file with mode: 0644]

index 2f97907..c13ad5c 100644 (file)
@@ -10,6 +10,7 @@ X.XXX.X (20XX-XX_XX)
     ・ベジェ補間パラメータ冗長部がMMDの版により異なるため、検査をやめた。
     ・プロセス終了コードの変更。
     ・DOMからSAXへの移行。
+    ・MikuMikuDance Ver7.40以降の新VMDファイルフォーマットに対応
 
 
 1.101.2 (2011-08-25)
diff --git a/pom.xml b/pom.xml
index 7b31956..5d30fcb 100644 (file)
--- a/pom.xml
+++ b/pom.xml
         <dependency>
             <groupId>jp.sourceforge.mikutoga</groupId>
             <artifactId>togagem</artifactId>
-            <version>2.102.5-SNAPSHOT</version>
+            <version>2.102.7-SNAPSHOT</version>
             <scope>compile</scope>
         </dependency>
 
diff --git a/src/main/java/jp/sfjp/mikutoga/vmd/model/IkSwitch.java b/src/main/java/jp/sfjp/mikutoga/vmd/model/IkSwitch.java
new file mode 100644 (file)
index 0000000..85d6df1
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * IK ON/OFF switch
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.vmd.model;
+
+import java.text.MessageFormat;
+
+/**
+ * IK ON/OFF の管理を行う。
+ */
+public class IkSwitch {
+
+    private static final String MSG_TXT =
+              "IKbone {0} : {1}";
+
+
+    private String boneName = "";
+    private boolean valid = true;
+
+
+    /**
+     * コンストラクタ。
+     */
+    public IkSwitch(){
+        super();
+        return;
+    }
+
+
+    /**
+     * ボーン名を返す。
+     * @return ボーン名
+     */
+    public String getBoneName(){
+        return this.boneName;
+    }
+
+    /**
+     * ボーン名を設定する。
+     * @param boneNameArg ボーン名
+     * @throws NullPointerException 引数がnull
+     */
+    public void setBoneName(String boneNameArg) throws NullPointerException{
+        if(boneNameArg == null) throw new NullPointerException();
+        this.boneName = boneNameArg;
+        return;
+    }
+
+    /**
+     * IK処理が有効か否か返す。
+     * @return 有効ならtrue
+     */
+    public boolean isValid(){
+        return this.valid;
+    }
+
+    /**
+     * IK処理が有効か否か設定する。
+     * @param validArg 有効ならtrue
+     */
+    public void setValid(boolean validArg){
+        this.valid = validArg;
+        return;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return {@inheritDoc}
+     */
+    @Override
+    public String toString(){
+        String msg;
+        msg = MessageFormat.format(MSG_TXT, this.boneName, this.valid);
+        return msg;
+    }
+
+}
diff --git a/src/main/java/jp/sfjp/mikutoga/vmd/model/NumberedVmdFlag.java b/src/main/java/jp/sfjp/mikutoga/vmd/model/NumberedVmdFlag.java
new file mode 100644 (file)
index 0000000..3e1a33b
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * model presence switch
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.vmd.model;
+
+import java.text.MessageFormat;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import jp.sfjp.mikutoga.vmd.AbstractNumbered;
+
+/**
+ * フレーム番号が付けられた各種モーションフラグの管理を行う。
+ */
+public class NumberedVmdFlag
+        extends AbstractNumbered
+        implements Iterable<IkSwitch> {
+
+    private static final String MSG_TXT =
+              "#{0} model precense : {1}";
+
+
+    private boolean shown = true;
+    private List<IkSwitch> ikSwList = new LinkedList<IkSwitch>();
+
+
+    /**
+     * コンストラクタ。
+     * <p>モデル表示ありの状態で初期化される。
+     */
+    public NumberedVmdFlag(){
+        super();
+        return;
+    }
+
+
+    /**
+     * モデルを表示するか否か返す。
+     * @return 表示するならtrue
+     */
+    public boolean isModelShown(){
+        return this.shown;
+    }
+
+    /**
+     * モデルを表示するか否か設定する。
+     * @param shownArg 表示するならtrue
+     */
+    public void setModelShown(boolean shownArg){
+        this.shown = shownArg;
+        return;
+    }
+
+    /**
+     * 個別IKボーンフラグのリストを返す。
+     * @return 個別IKボーンフラグのリスト
+     */
+    public List<IkSwitch> getIkSwitchList(){
+        return this.ikSwList;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return {@inheritDoc}
+     */
+    @Override
+    public Iterator<IkSwitch> iterator(){
+        return this.ikSwList.iterator();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @return {@inheritDoc}
+     */
+    @Override
+    public String toString(){
+        String msg;
+        msg = MessageFormat.format(MSG_TXT, getFrameNumber(), this.shown);
+
+        StringBuilder submsg = new StringBuilder(msg);
+        for(IkSwitch sw : this.ikSwList){
+            submsg.append('\n').append("\u0020").append(sw.toString());
+        }
+
+        return submsg.toString();
+    }
+
+}
index a006061..c06561c 100644 (file)
@@ -22,8 +22,8 @@ import jp.sfjp.mikutoga.vmd.VmdUniq;
 public class VmdMotion {
 
     private static final String MSG_TXT =
-              "model name : {0}\n"
-            + "bone#{1} morph#{2} camera#{3} luminous#{4} shadow#{5}";
+          "model name : {0}\n"
+        + "bone#{1} morph#{2} camera#{3} luminous#{4} shadow#{5} flag#{6}";
 
 
     private String modelName = VmdUniq.MODELNAME_STAGEACT;
@@ -31,9 +31,10 @@ public class VmdMotion {
     private final Map<String, List<BoneMotion>>  bonePartMap;
     private final Map<String, List<MorphMotion>> morphPartMap;
 
-    private final List<CameraMotion>   cameraMotionList;
-    private final List<LuminousMotion> luminousMotionList;
-    private final List<ShadowMotion>   shadowMotionList;
+    private final List<CameraMotion>    cameraMotionList;
+    private final List<LuminousMotion>  luminousMotionList;
+    private final List<ShadowMotion>    shadowMotionList;
+    private final List<NumberedVmdFlag> flagList;
 
 
     /**
@@ -48,6 +49,7 @@ public class VmdMotion {
         this.cameraMotionList   = new LinkedList<CameraMotion>();
         this.luminousMotionList = new LinkedList<LuminousMotion>();
         this.shadowMotionList   = new LinkedList<ShadowMotion>();
+        this.flagList           = new LinkedList<NumberedVmdFlag>();
 
         return;
     }
@@ -132,6 +134,14 @@ public class VmdMotion {
     }
 
     /**
+     * 各種フレーム番号付きフラグのリストを返す。
+     * @return フレーム番号付きフラグのリスト
+     */
+    public List<NumberedVmdFlag> getNumberedFlagList(){
+        return this.flagList;
+    }
+
+    /**
      * ボーンモーションを追加する。
      * 追加順は保持される。
      * @param motion ボーンモーション
@@ -186,6 +196,7 @@ public class VmdMotion {
         Collections.sort(this.cameraMotionList,   FrameNumbered.COMPARATOR);
         Collections.sort(this.luminousMotionList, FrameNumbered.COMPARATOR);
         Collections.sort(this.shadowMotionList,   FrameNumbered.COMPARATOR);
+        Collections.sort(this.flagList,           FrameNumbered.COMPARATOR);
 
         return;
     }
@@ -209,11 +220,12 @@ public class VmdMotion {
         int cameraNo   = this.cameraMotionList  .size();
         int luminousNo = this.luminousMotionList.size();
         int shadowNo   = this.shadowMotionList  .size();
+        int flagNo     = this.flagList          .size();
 
         String msg;
         msg = MessageFormat.format(MSG_TXT,
                 this.modelName,
-                boneNo, morphNo, cameraNo, luminousNo, shadowNo );
+                boneNo, morphNo, cameraNo, luminousNo, shadowNo, flagNo );
 
         return msg;
     }
diff --git a/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolExporter.java b/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolExporter.java
new file mode 100644 (file)
index 0000000..e43bb65
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * boolean information exporter
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.vmd.model.binio;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+import jp.sfjp.mikutoga.bin.export.BinaryExporter;
+import jp.sfjp.mikutoga.bin.export.IllegalTextExportException;
+import jp.sfjp.mikutoga.vmd.VmdConst;
+import jp.sfjp.mikutoga.vmd.model.IkSwitch;
+import jp.sfjp.mikutoga.vmd.model.NumberedVmdFlag;
+import jp.sfjp.mikutoga.vmd.model.VmdMotion;
+
+/**
+ * フラグ情報のエクスポーター。
+ * <p>MikuMikuDance Ver7.40以降でサポート
+ */
+class BoolExporter extends BinaryExporter{
+
+    private static final byte[] FDFILLER =
+        { (byte)0x00, (byte)0xfd };
+
+
+    /**
+     * コンストラクタ。
+     * @param stream 出力ストリーム
+     */
+    BoolExporter(OutputStream stream){
+        super(stream);
+        return;
+    }
+
+
+    /**
+     * フラグ情報を出力する。
+     * @param motion モーションデータ
+     * @throws IOException 出力エラー
+     * @throws IllegalTextExportException 不正な文字列が指定された。
+     */
+    void dumpNumberedFlagMotion(VmdMotion motion)
+            throws IOException, IllegalTextExportException {
+        List<NumberedVmdFlag> list = motion.getNumberedFlagList();
+
+        if(list.isEmpty()) return;
+
+        int count = list.size();
+        dumpLeInt(count);
+
+        for(NumberedVmdFlag flag : list){
+            int frameNo = flag.getFrameNumber();
+            dumpLeInt(frameNo);
+
+            byte showModel;
+            if(flag.isModelShown()) showModel = 0x01;
+            else                    showModel = 0x00;
+            dumpByte(showModel);
+
+            dumpIkSwitch(flag);
+        }
+
+
+        return;
+    }
+
+    /**
+     * IK有効フラグを出力する。
+     * @param flag フラグ情報
+     * @throws IOException 出力エラー
+     * @throws IllegalTextExportException 不正な文字列が指定された。
+     */
+    private void dumpIkSwitch(NumberedVmdFlag flag)
+            throws IOException, IllegalTextExportException {
+        List<IkSwitch> swList = flag.getIkSwitchList();
+        int swNo = swList.size();
+        dumpLeInt(swNo);
+
+        for(IkSwitch ikSwitch : swList){
+            String boneName = ikSwitch.getBoneName();
+            dumpFixedW31j(boneName, VmdConst.IKSWBONENAME_MAX, FDFILLER);
+
+            byte ikValid;
+            if(ikSwitch.isValid()) ikValid = 0x01;
+            else                   ikValid = 0x00;
+            dumpByte(ikValid);
+        }
+
+        return;
+    }
+
+}
diff --git a/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolLoader.java b/src/main/java/jp/sfjp/mikutoga/vmd/model/binio/BoolLoader.java
new file mode 100644 (file)
index 0000000..208dd8f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * boolean information builder
+ *
+ * License : The MIT License
+ * Copyright(c) 2013 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.vmd.model.binio;
+
+import java.util.List;
+import jp.sfjp.mikutoga.bin.parser.MmdFormatException;
+import jp.sfjp.mikutoga.bin.parser.ParseStage;
+import jp.sfjp.mikutoga.vmd.model.IkSwitch;
+import jp.sfjp.mikutoga.vmd.model.NumberedVmdFlag;
+import jp.sfjp.mikutoga.vmd.model.VmdMotion;
+import jp.sfjp.mikutoga.vmd.parser.VmdBoolHandler;
+
+/**
+ * フラグ情報のビルダ。
+ * <p>MikuMikuDance Ver7.40以降でサポート
+ */
+public class BoolLoader implements VmdBoolHandler{
+
+    private final List<NumberedVmdFlag> flagList;
+
+    private NumberedVmdFlag currentFlag;
+    private IkSwitch currentSwitch;
+
+    /**
+     * コンストラクタ。
+     * @param vmdMotion モーションデータの格納先。
+     */
+    BoolLoader(VmdMotion vmdMotion){
+        super();
+        this.flagList = vmdMotion.getNumberedFlagList();
+        return;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @param stage {@inheritDoc}
+     * @param loops {@inheritDoc}
+     * @throws MmdFormatException {@inheritDoc}
+     */
+    @Override
+    public void loopStart(ParseStage stage, int loops)
+            throws MmdFormatException{
+        if(stage == VmdBoolHandler.MODELSIGHT_LIST){
+            this.currentFlag = new NumberedVmdFlag();
+        }else if(stage == VmdBoolHandler.IKSW_LIST){
+            this.currentSwitch = new IkSwitch();
+        }
+
+        return;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @param stage {@inheritDoc}
+     * @throws MmdFormatException {@inheritDoc}
+     */
+    @Override
+    public void loopNext(ParseStage stage)
+            throws MmdFormatException{
+        if(stage == VmdBoolHandler.MODELSIGHT_LIST){
+            this.flagList.add(this.currentFlag);
+            this.currentFlag = new NumberedVmdFlag();
+        }else if(stage == VmdBoolHandler.IKSW_LIST){
+            List<IkSwitch> swList = this.currentFlag.getIkSwitchList();
+            swList.add(this.currentSwitch);
+            this.currentSwitch = new IkSwitch();
+        }
+
+        return;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @param stage {@inheritDoc}
+     * @throws MmdFormatException {@inheritDoc}
+     */
+    @Override
+    public void loopEnd(ParseStage stage)
+            throws MmdFormatException{
+        if(stage == VmdBoolHandler.MODELSIGHT_LIST){
+            this.currentFlag = null;
+        }else if(stage == VmdBoolHandler.IKSW_LIST){
+            this.currentSwitch = null;
+        }
+
+        return;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @param show {@inheritDoc}
+     * @param keyFrameNo {@inheritDoc}
+     * @throws MmdFormatException {@inheritDoc}
+     */
+    @Override
+    public void vmdModelSight(boolean show, int keyFrameNo)
+            throws MmdFormatException {
+        this.currentFlag.setModelShown(show);
+        this.currentFlag.setFrameNumber(keyFrameNo);
+        return;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @param boneName {@inheritDoc}
+     * @param validIk {@inheritDoc}
+     * @param keyFrameNo {@inheritDoc}
+     * @throws MmdFormatException {@inheritDoc}
+     */
+    @Override
+    public void vmdIkSwitch(String boneName,
+                              boolean validIk,
+                              int keyFrameNo )
+            throws MmdFormatException {
+        this.currentSwitch.setBoneName(boneName);
+        this.currentSwitch.setValid(validIk);
+        return;
+    }
+
+}
index e04dfd9..1d372e0 100644 (file)
@@ -21,6 +21,7 @@ public class VmdExporter {
     private BasicExporter    basicExporter = null;
     private CameraExporter   cameraExporter = null;
     private LightingExporter lightingExporter = null;
+    private BoolExporter     boolExporter = null;
 
 
     /**
@@ -44,6 +45,7 @@ public class VmdExporter {
         this.basicExporter    = new BasicExporter(ostream);
         this.cameraExporter   = new CameraExporter(ostream);
         this.lightingExporter = new LightingExporter(ostream);
+        this.boolExporter     = new BoolExporter(ostream);
 
         try{
             dumpVmdMotionImpl(motion);
@@ -76,6 +78,13 @@ public class VmdExporter {
         this.lightingExporter.dumpLuminousMotion(motion);
         this.lightingExporter.dumpShadowMotion(motion);
 
+        if(motion.getNumberedFlagList().isEmpty()) return;
+        try{
+            this.boolExporter.dumpNumberedFlagMotion(motion);
+        }catch(IllegalTextExportException e){
+            throw new IllegalVmdDataException(e);
+        }
+
         return;
     }
 
index be7d841..e832b6b 100644 (file)
@@ -25,7 +25,6 @@ public class VmdLoader {
     private boolean loaded = false;
     private boolean hasMoreData = true;
 
-    private boolean ignoreName = true;
     private boolean redundantCheck = false;
 
 
@@ -49,23 +48,11 @@ public class VmdLoader {
     }
 
     /**
-     * カメラ・ライティングデータのパースを試みるか否かの判断で、
-     * 特殊モデル名判定を無視するか否か設定する。
-     * デフォルトではモデル名を無視。
-     * <p>※MMDVer7.30前後のVMD出力不具合を回避したい場合は、
-     * オフにするとパースに成功する場合がある。
-     * @param mode モデル名を無視してパースを強行するならtrue
-     */
-    public void setIgnoreName(boolean mode){
-        this.ignoreName = mode;
-        return;
-    }
-
-    /**
      * ボーンモーション補間情報冗長部のチェックを行うか否か設定する。
      * デフォルトではチェックを行わない。
      * <p>※MMDVer7.30前後のVMD出力不具合を回避したい場合は、
      * オフにするとパースに成功する場合がある。
+     * <p>※MMD Ver7.39x64以降はチェック回避必須。
      * @param mode チェックさせたければtrue
      */
     public void setRedundantCheck(boolean mode){
@@ -92,16 +79,17 @@ public class VmdLoader {
 
         VmdParser parser = new VmdParser(source);
 
-        parser.setIgnoreName(this.ignoreName);
         parser.setRedundantCheck(this.redundantCheck);
 
         BasicLoader basicBuilder       = new BasicLoader(motion);
         CameraLoader cameraBuilder     = new CameraLoader(motion);
         LightingLoader lightingBuilder = new LightingLoader(motion);
+        BoolLoader boolBuilder         = new BoolLoader(motion);
 
         parser.setBasicHandler(basicBuilder);
         parser.setCameraHandler(cameraBuilder);
         parser.setLightingHandler(lightingBuilder);
+        parser.setBoolHandler(boolBuilder);
 
         try{
             parser.parseVmd();
@@ -13,24 +13,35 @@ import org.xml.sax.Attributes;
 /**
  * XSD各種型のSAX属性値をJavaプリミティブ型へ変換する。
  */
-final class SaxXsdUtil {
+public final class SaxAttr {
 
     /**
      * 隠しコンストラクタ。
      */
-    private SaxXsdUtil(){
+    private SaxAttr(){
         assert false;
         throw new AssertionError();
     }
 
 
     /**
+     * 属性名に対応する属性値があるか否か判定する。
+     * @param attr 属性群
+     * @param name 属性名
+     * @return 属性名に対応する属性値がある場合はtrue
+     */
+    public static boolean hasAttr(Attributes attr, String name){
+        if(attr.getValue(name) == null) return false;
+        return true;
+    }
+
+    /**
      * xsd:string型属性値の読み込み。
      * @param attr 属性群
      * @param name 属性名
      * @return 属性値。該当する属性が無ければnull。
      */
-    static String getStringAttr(Attributes attr, String name){
+    public static String getStringAttr(Attributes attr, String name){
         String attrVal = attr.getValue(name);
         return attrVal;
     }
@@ -42,7 +53,7 @@ final class SaxXsdUtil {
      * @return 属性値。
      * @throws IllegalArgumentException boolean型表記ではない
      */
-    static boolean getBooleanAttr(Attributes attr, String name)
+    public static boolean getBooleanAttr(Attributes attr, String name)
             throws IllegalArgumentException{
         String attrVal = attr.getValue(name);
         boolean bVal;
@@ -58,7 +69,9 @@ final class SaxXsdUtil {
      * @return 属性値。
      * @throws IllegalArgumentException boolean型表記ではない
      */
-    static boolean getBooleanAttr(Attributes attr, String name, boolean def)
+    public static boolean getBooleanAttr(Attributes attr,
+                                           String name,
+                                           boolean def )
             throws IllegalArgumentException{
         String attrVal = attr.getValue(name);
         if(attrVal == null) return def;
@@ -76,7 +89,7 @@ final class SaxXsdUtil {
      * @return 属性値。
      * @throws NumberFormatException byte型表記ではない
      */
-    static byte getByteAttr(Attributes attr, String name)
+    public static byte getByteAttr(Attributes attr, String name)
             throws NumberFormatException{
         String attrVal = attr.getValue(name);
         byte bVal;
@@ -91,7 +104,7 @@ final class SaxXsdUtil {
      * @return 属性値。
      * @throws NumberFormatException float型表記ではない
      */
-    static float getFloatAttr(Attributes attr, String name)
+    public static float getFloatAttr(Attributes attr, String name)
             throws NumberFormatException {
         String attrVal = attr.getValue(name);
         float fVal;
@@ -106,7 +119,7 @@ final class SaxXsdUtil {
      * @return 属性値。
      * @throws NumberFormatException int型表記ではない
      */
-    static int getIntAttr(Attributes attr, String name)
+    public static int getIntAttr(Attributes attr, String name)
             throws NumberFormatException {
         String attrVal = attr.getValue(name);
         int iVal;
index 116777b..e29a620 100644 (file)
@@ -98,13 +98,13 @@ class SaxCameraListener extends SaxVmdListener{
     private void openCameraMotion(Attributes attr){
         this.currentCamera = new CameraMotion();
 
-        int frameNo = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_FRAME);
+        int frameNo = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_FRAME);
         this.currentCamera.setFrameNumber(frameNo);
 
         boolean hasPerspective =
-                SaxXsdUtil.getBooleanAttr(attr,
-                                          XmlAttr.ATTR_HAS_PERSPECTIVE,
-                                          true );
+                SaxAttr.getBooleanAttr(attr,
+                                       XmlAttr.ATTR_HAS_PERSPECTIVE,
+                                       true );
         this.currentCamera.setPerspectiveMode(hasPerspective);
 
         return;
@@ -130,9 +130,9 @@ class SaxCameraListener extends SaxVmdListener{
     private void openCameraTarget(Attributes attr){
         MkPos3D targetPos = this.currentCamera.getCameraTarget();
 
-        float xPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_X_POS);
-        float yPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Y_POS);
-        float zPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Z_POS);
+        float xPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_X_POS);
+        float yPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Y_POS);
+        float zPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Z_POS);
 
         targetPos.setPosition(xPos, yPos, zPos);
 
@@ -150,9 +150,9 @@ class SaxCameraListener extends SaxVmdListener{
         CameraRotation cameraRotation =
                 this.currentCamera.getCameraRotation();
 
-        float latitude  = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_X_RAD);
-        float longitude = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Y_RAD);
-        float roll      = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Z_RAD);
+        float latitude  = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_X_RAD);
+        float longitude = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Y_RAD);
+        float roll      = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Z_RAD);
 
         cameraRotation.setLatitude(latitude);
         cameraRotation.setLongitude(longitude);
@@ -169,7 +169,7 @@ class SaxCameraListener extends SaxVmdListener{
      * @param attr 属性群
      */
     private void openCameraRange(Attributes attr){
-        float range = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_RANGE);
+        float range = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_RANGE);
         this.currentCamera.setRange(range);
 
         BezierParam bez = this.currentCamera.getIntpltRange();
@@ -183,7 +183,7 @@ class SaxCameraListener extends SaxVmdListener{
      * @param attr 属性群
      */
     private void openProjection(Attributes attr){
-        int vertDeg = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_VERT_DEG);
+        int vertDeg = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_VERT_DEG);
         this.currentCamera.setProjectionAngle(vertDeg);
 
         BezierParam bez = this.currentCamera.getIntpltProjection();
index 7386d0d..9cfe45a 100644 (file)
@@ -79,7 +79,7 @@ class SaxLightingListener extends SaxVmdListener{
     private void openLumiAct(Attributes attr){
         this.currentLuminous = new LuminousMotion();
 
-        int frameNo = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_FRAME);
+        int frameNo = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_FRAME);
         this.currentLuminous.setFrameNumber(frameNo);
 
         return;
@@ -105,9 +105,9 @@ class SaxLightingListener extends SaxVmdListener{
     private void openLumiColor(Attributes attr){
         LuminousColor color = this.currentLuminous.getColor();
 
-        float rCol = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_R_COL);
-        float gCol = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_G_COL);
-        float bCol = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_B_COL);
+        float rCol = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_R_COL);
+        float gCol = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_G_COL);
+        float bCol = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_B_COL);
 
         color.setColR(rCol);
         color.setColG(gCol);
@@ -123,9 +123,9 @@ class SaxLightingListener extends SaxVmdListener{
     private void openLumiDirection(Attributes attr){
         MkVec3D vec = this.currentLuminous.getDirection();
 
-        float xVec = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_X_VEC);
-        float yVec = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Y_VEC);
-        float zVec = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Z_VEC);
+        float xVec = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_X_VEC);
+        float yVec = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Y_VEC);
+        float zVec = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Z_VEC);
 
         vec.setXVal(xVec);
         vec.setYVal(yVec);
@@ -141,15 +141,15 @@ class SaxLightingListener extends SaxVmdListener{
     private void openShadowAct(Attributes attr){
         ShadowMotion shadowMotion = new ShadowMotion();
 
-        int frameNo = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_FRAME);
+        int frameNo = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_FRAME);
         shadowMotion.setFrameNumber(frameNo);
 
         float rawParam =
-                SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_RAW_PARAM);
+                SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_RAW_PARAM);
         shadowMotion.setRawScopeParam(rawParam);
 
         String modeAttr =
-                SaxXsdUtil.getStringAttr(attr, XmlAttr.ATTR_MODE);
+                SaxAttr.getStringAttr(attr, XmlAttr.ATTR_MODE);
         ShadowMode mode = ShadowMode.valueOf(modeAttr);
         shadowMotion.setShadowMode(mode);
 
index b25a150..3cd616b 100644 (file)
@@ -104,7 +104,7 @@ class SaxMotionListener extends SaxVmdListener{
      * @param attr 属性群
      */
     private void openBonePart(Attributes attr){
-        this.boneName = SaxXsdUtil.getStringAttr(attr, XmlAttr.ATTR_NAME);
+        this.boneName = SaxAttr.getStringAttr(attr, XmlAttr.ATTR_NAME);
         return;
     }
 
@@ -116,7 +116,7 @@ class SaxMotionListener extends SaxVmdListener{
         this.boneMotion = new BoneMotion();
         this.boneMotion.setBoneName(this.boneName);
 
-        int frameNo = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_FRAME);
+        int frameNo = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_FRAME);
         this.boneMotion.setFrameNumber(frameNo);
 
         return;
@@ -138,9 +138,9 @@ class SaxMotionListener extends SaxVmdListener{
     private void openBonePosition(Attributes attr){
         MkPos3D position = this.boneMotion.getPosition();
 
-        float xPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_X_POS);
-        float yPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Y_POS);
-        float zPos = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Z_POS);
+        float xPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_X_POS);
+        float yPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Y_POS);
+        float zPos = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Z_POS);
 
         position.setXpos(xPos);
         position.setYpos(yPos);
@@ -159,10 +159,10 @@ class SaxMotionListener extends SaxVmdListener{
     private void openBoneRotQuat(Attributes attr){
         MkQuat rotation = this.boneMotion.getRotation();
 
-        float qx = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_QX);
-        float qy = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_QY);
-        float qz = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_QZ);
-        float qw = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_QW);
+        float qx = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_QX);
+        float qy = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_QY);
+        float qz = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_QZ);
+        float qw = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_QW);
 
         rotation.setQ1(qx);
         rotation.setQ2(qy);
@@ -182,9 +182,9 @@ class SaxMotionListener extends SaxVmdListener{
     private void openBoneRotEyxz(Attributes attr){
         MkQuat rotation = this.boneMotion.getRotation();
 
-        float xDeg = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_X_DEG);
-        float yDeg = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Y_DEG);
-        float zDeg = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_Z_DEG);
+        float xDeg = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_X_DEG);
+        float yDeg = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Y_DEG);
+        float zDeg = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_Z_DEG);
 
         float xRad = (float)StrictMath.toRadians(xDeg);
         float yRad = (float)StrictMath.toRadians(yDeg);
@@ -203,7 +203,7 @@ class SaxMotionListener extends SaxVmdListener{
      * @param attr 属性群
      */
     private void openMorphPart(Attributes attr){
-        this.morphName = SaxXsdUtil.getStringAttr(attr, XmlAttr.ATTR_NAME);
+        this.morphName = SaxAttr.getStringAttr(attr, XmlAttr.ATTR_NAME);
         return;
     }
 
@@ -214,8 +214,8 @@ class SaxMotionListener extends SaxVmdListener{
     private void openMorphMotion(Attributes attr){
         MorphMotion morphMotion = new MorphMotion();
 
-        int frameNo = SaxXsdUtil.getIntAttr(attr, XmlAttr.ATTR_FRAME);
-        float flex = SaxXsdUtil.getFloatAttr(attr, XmlAttr.ATTR_FLEX);
+        int frameNo = SaxAttr.getIntAttr(attr, XmlAttr.ATTR_FRAME);
+        float flex = SaxAttr.getFloatAttr(attr, XmlAttr.ATTR_FLEX);
 
         morphMotion.setMorphName(this.morphName);
         morphMotion.setFrameNumber(frameNo);
index 3e8cc5d..dfc1aa5 100644 (file)
@@ -175,10 +175,10 @@ class SaxVmdListener {
      * @param attr 属性群
      */
     protected void openBezier(Attributes attr){
-        byte p1x = SaxXsdUtil.getByteAttr(attr, XmlAttr.ATTR_P1X);
-        byte p1y = SaxXsdUtil.getByteAttr(attr, XmlAttr.ATTR_P1Y);
-        byte p2x = SaxXsdUtil.getByteAttr(attr, XmlAttr.ATTR_P2X);
-        byte p2y = SaxXsdUtil.getByteAttr(attr, XmlAttr.ATTR_P2Y);
+        byte p1x = SaxAttr.getByteAttr(attr, XmlAttr.ATTR_P1X);
+        byte p1y = SaxAttr.getByteAttr(attr, XmlAttr.ATTR_P1Y);
+        byte p2x = SaxAttr.getByteAttr(attr, XmlAttr.ATTR_P2X);
+        byte p2y = SaxAttr.getByteAttr(attr, XmlAttr.ATTR_P2Y);
 
         putBezier(p1x, p1y, p2x, p2y);
 
index 7cf32eb..88a7317 100644 (file)
@@ -129,7 +129,7 @@ class XmlHandler implements ContentHandler{
 
         if(tag == VmdTag.MODEL_NAME){
             String modelName =
-                    SaxXsdUtil.getStringAttr(attr, XmlAttr.ATTR_NAME);
+                    SaxAttr.getStringAttr(attr, XmlAttr.ATTR_NAME);
             this.vmdMotion.setModelName(modelName);
             return;
         }
index 3decd1d..1b0135e 100644 (file)
@@ -401,7 +401,6 @@ public class Vmd2XmlConv {
             throws IOException, MmdFormatException{
         VmdLoader loader = new VmdLoader();
 
-        loader.setIgnoreName(true);
         loader.setRedundantCheck(false);
 
         VmdMotion motion = loader.load(is);
diff --git a/src/main/resources/jp/sfjp/mikutoga/vmd/model/xml/resources/vmdxml-130609A.xsd b/src/main/resources/jp/sfjp/mikutoga/vmd/model/xml/resources/vmdxml-130609A.xsd
new file mode 100644 (file)
index 0000000..d1109fd
--- /dev/null
@@ -0,0 +1,944 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+  MikuMikuDance
+    motion-data(*.vmd) on XML
+    schema definition
+
+  License : The MIT License
+  Copyright(c) 2013 MikuToga Partners
+-->
+
+
+<!DOCTYPE xsd:schema [
+    <!ENTITY schemaVer "130609A" >
+    <!ENTITY schemaNS "http://mikutoga.sourceforge.jp/xml/ns/vmdxml/130609A" >
+]>
+
+
+<xsd:schema
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+
+    targetNamespace="&schemaNS;"
+    xmlns:tns      ="&schemaNS;"
+
+    elementFormDefault="qualified"
+    version="&schemaVer;"
+>
+
+    <xsd:annotation>
+        <xsd:documentation>
+            MikuMikuDance motion-data(*.vmd) on XML.
+            License : The MIT License
+            Copyright(c) 2013 MikuToga Partners
+        </xsd:documentation>
+    </xsd:annotation>
+
+
+    <!-- ROOT element for motion -->
+    <xsd:element name="vmdMotion" >
+        <xsd:annotation>
+            <xsd:documentation>
+                Root element.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:meta"
+                    minOccurs="0" maxOccurs="unbounded" />
+                <xsd:choice>
+                    <xsd:sequence>  <!-- model motion -->
+                        <xsd:element ref="tns:modelName" />
+                        <xsd:element ref="tns:boneMotionSequence" />
+                        <xsd:element ref="tns:morphSequence" />
+                        <xsd:element ref="tns:flagSequence" />
+                    </xsd:sequence>
+                    <xsd:sequence>  <!-- stage act -->
+                        <xsd:element ref="tns:cameraSequence" />
+                        <xsd:element ref="tns:luminousSequence" />
+                        <xsd:element ref="tns:shadowSequence" />
+                    </xsd:sequence>
+                </xsd:choice>
+            </xsd:sequence>
+            <xsd:attribute
+                name="version"
+                type="xsd:token"
+                use="required"
+                fixed="&schemaVer;" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:simpleType name="FrameNo" >
+        <xsd:annotation>
+            <xsd:documentation>
+                frame No.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:int" >
+<!--
+            <xsd:minInclusive value="0" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="MorphFlex" >
+        <xsd:annotation>
+            <xsd:documentation>
+                morph flexible value. [0.0-1.0]
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:float" >
+            <xsd:minInclusive value="-0.0" />
+<!--
+            <xsd:maxInclusive value="1.0" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="ProjectionAngle" >
+        <xsd:annotation>
+            <xsd:documentation>
+                screen-projection angle(degree).
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:int" >
+<!--
+            <xsd:minInclusive value="-0" />
+            <xsd:maxInclusive value="+180" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="ColorComponent" >
+        <xsd:annotation>
+            <xsd:documentation>
+                color component value.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:float" >
+<!--
+            <xsd:minInclusive value="-0.0" />
+            <xsd:maxInclusive value="1.0" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="DirVecComponent" >
+        <xsd:annotation>
+            <xsd:documentation>
+                direction vector component value.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:float" >
+<!--
+            <xsd:minInclusive value="-1.0" />
+            <xsd:maxInclusive value="+1.0" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="ShadowType" >
+        <xsd:annotation>
+            <xsd:documentation>
+                type of shadow
+                + NONE   : no self-shadow
+                + MODE_1 : reduce shadow-quality suddenly at range
+                + MODE_2 : reduce shadow-quality gradually with range
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:string" >
+            <xsd:enumeration value="NONE"   />
+            <xsd:enumeration value="MODE_1" />
+            <xsd:enumeration value="MODE_2" />
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="ShadowRawParam" >
+        <xsd:annotation>
+            <xsd:documentation>
+                shadow range raw value.
+
+                UI_VALUE = EFFECTIVE_RANGE * 100 ???
+                rawParam = 0.1 - (UI_VALUE / 1.0E+5)
+
+                UI_VALUE:0    => rawParam:0.1
+                UI_VALUE:8875 => rawParam:0.01125
+                UI_VALUE:9999 => rawParam:1.0E-5
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:float" >
+<!--
+            <xsd:minInclusive value="-0.0" />
+            <xsd:maxInclusive value="0.1" />
+-->
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:simpleType name="BezPt" >
+        <xsd:annotation>
+            <xsd:documentation>
+                Bezier points coordinates value. [XY:0-127]
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:restriction base="xsd:byte" >
+            <xsd:minInclusive value=  "0" />
+            <xsd:maxInclusive value="127" />
+        </xsd:restriction>
+
+    </xsd:simpleType>
+
+
+    <xsd:complexType name="FrameNumbered" >
+        <xsd:annotation>
+            <xsd:documentation>
+                frame numbered type.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:attribute name="frame" type="tns:FrameNo" use="required" />
+
+    </xsd:complexType>
+
+
+    <xsd:complexType name="BezParam" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bezier cubic curve parameters.
+                p0=(0, 0) p3=(127, 127) [implicit points]
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:attribute name="p1x" type="tns:BezPt" use="optional" />
+        <xsd:attribute name="p1y" type="tns:BezPt" use="optional" />
+        <xsd:attribute name="p2x" type="tns:BezPt" use="optional" />
+        <xsd:attribute name="p2y" type="tns:BezPt" use="optional" />
+
+    </xsd:complexType>
+
+
+    <xsd:element name="bezier" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bezier cubic curve parameters.
+                p0=(0, 0) p3=(127, 127) [implicit points]
+                P1 and P2 points are required.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:restriction base="tns:BezParam" >
+                    <xsd:attribute name="p1x" type="tns:BezPt" use="required" />
+                    <xsd:attribute name="p1y" type="tns:BezPt" use="required" />
+                    <xsd:attribute name="p2x" type="tns:BezPt" use="required" />
+                    <xsd:attribute name="p2y" type="tns:BezPt" use="required" />
+                </xsd:restriction>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="defLinear" >
+        <xsd:annotation>
+            <xsd:documentation>
+                default linear bezier curve.
+                p0=(0, 0) p1=(20, 20) p2=(107, 107) p3=(127, 127)
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:restriction base="tns:BezParam" >
+                    <xsd:attribute name="p1x" use="prohibited" fixed= "20" />
+                    <xsd:attribute name="p1y" use="prohibited" fixed= "20" />
+                    <xsd:attribute name="p2x" use="prohibited" fixed="107" />
+                    <xsd:attribute name="p2y" use="prohibited" fixed="107" />
+                </xsd:restriction>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="defEaseInOut" >
+        <xsd:annotation>
+            <xsd:documentation>
+                default ease-in-out bezier curve.
+                p0=(0, 0) p1=(64, 0) p2=(64, 127) p3=(127, 127)
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:restriction base="tns:BezParam" >
+                    <xsd:attribute name="p1x" use="prohibited" fixed= "64" />
+                    <xsd:attribute name="p1y" use="prohibited" fixed=  "0" />
+                    <xsd:attribute name="p2x" use="prohibited" fixed= "64" />
+                    <xsd:attribute name="p2y" use="prohibited" fixed="127" />
+                </xsd:restriction>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:complexType name="InterpolationSingle" >
+        <xsd:annotation>
+            <xsd:documentation>
+                has single interpolation curve.
+                If omitted, it means default linear curve.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:choice minOccurs="0" >
+            <xsd:element ref="tns:bezier" />
+            <xsd:element ref="tns:defLinear" />
+            <xsd:element ref="tns:defEaseInOut" />
+        </xsd:choice>
+
+    </xsd:complexType>
+
+
+    <xsd:complexType name="PosWithInterpolation" >
+        <xsd:annotation>
+            <xsd:documentation>
+                3D-position with XYZ-interpolation curve.
+                If omitted, it means default linear curve *3 [XYZ].
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:sequence minOccurs="0" maxOccurs="1" >
+            <xsd:choice minOccurs="3" maxOccurs="3" >
+                <xsd:element ref="tns:bezier" />
+                <xsd:element ref="tns:defLinear" />
+                <xsd:element ref="tns:defEaseInOut" />
+            </xsd:choice>
+        </xsd:sequence>
+
+        <xsd:attribute name="xPos" type="xsd:float" use="required" />
+        <xsd:attribute name="yPos" type="xsd:float" use="required" />
+        <xsd:attribute name="zPos" type="xsd:float" use="required" />
+
+    </xsd:complexType>
+
+
+    <xsd:element name="meta" >
+        <xsd:annotation>
+            <xsd:documentation>
+                Meta-information of motion.
+                Use free.
+                but, some meta-name has recommended usage.
+                + "generator" (Generator application name)
+                + "siteURL" (about motion creator)
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:attribute
+                name="name"
+                type="xsd:NCName"
+                use="required" />
+            <xsd:attribute
+                name="content"
+                type="xsd:string"
+                use="required" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="modelName" >
+        <xsd:annotation>
+            <xsd:documentation>
+                name of motion-model.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:attribute
+                name="name"
+                type="xsd:string"
+                use="required" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="boneMotionSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone motion data sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:bonePart"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="BoneName" >
+            <xsd:selector xpath="./tns:bonePart" />
+            <xsd:field xpath="@name" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="bonePart" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone motion data group by bone-name.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:boneMotion"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+
+            <xsd:attribute
+                name="name"
+                type="xsd:string"
+                use="required" />
+        </xsd:complexType>
+
+        <xsd:unique name="BoneFrameNo" >
+            <xsd:selector xpath="./tns:boneMotion" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="boneMotion" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone motion data.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:sequence>
+                        <xsd:element
+                            ref="tns:bonePosition"
+                            minOccurs="0" maxOccurs="1" />
+                        <xsd:choice>
+                            <xsd:element ref="tns:boneRotQuat" />
+                            <xsd:element ref="tns:boneRotEyxz" />
+                        </xsd:choice>
+                    </xsd:sequence>
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="bonePosition" type="tns:PosWithInterpolation" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone position.
+            </xsd:documentation>
+        </xsd:annotation>
+
+    </xsd:element>
+
+
+    <xsd:element name="boneRotQuat" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone rotation. (Quaternion parameters)
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:InterpolationSingle" >
+                    <xsd:attribute name="qx" type="xsd:float" use="required" />
+                    <xsd:attribute name="qy" type="xsd:float" use="required" />
+                    <xsd:attribute name="qz" type="xsd:float" use="required" />
+                    <xsd:attribute name="qw" type="xsd:float" use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="boneRotEyxz" >
+        <xsd:annotation>
+            <xsd:documentation>
+                bone rotation. (YXZ-Euler rotation parameters)
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:InterpolationSingle" >
+                    <xsd:attribute name="xDeg" type="xsd:float" use="required" />
+                    <xsd:attribute name="yDeg" type="xsd:float" use="required" />
+                    <xsd:attribute name="zDeg" type="xsd:float" use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="morphSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                morphing data sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:morphPart"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="MorphName" >
+            <xsd:selector xpath="./tns:morphPart" />
+            <xsd:field xpath="@name" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="morphPart" >
+        <xsd:annotation>
+            <xsd:documentation>
+                morphing data group by morph-name.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:morphMotion"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+
+            <xsd:attribute
+                name="name"
+                type="xsd:string"
+                use="required" />
+        </xsd:complexType>
+
+        <xsd:unique name="MorphFrameNo" >
+            <xsd:selector xpath="./tns:morphMotion" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="morphMotion" >
+        <xsd:annotation>
+            <xsd:documentation>
+                morphing data.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:attribute
+                        name="flex"
+                        type="tns:MorphFlex"
+                        use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="cameraSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                camera sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:cameraMotion"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="CameraFrameNo" >
+            <xsd:selector xpath="./tns:cameraMotion" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="cameraMotion" >
+        <xsd:annotation>
+            <xsd:documentation>
+                camera data.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:sequence>
+                        <xsd:element ref="tns:cameraTarget" />
+                        <xsd:element ref="tns:cameraRotation" />
+                        <xsd:element ref="tns:cameraRange" />
+                        <xsd:element ref="tns:projection" />
+                    </xsd:sequence>
+                    <xsd:attribute
+                        name="hasPerspective"
+                        type="xsd:boolean"
+                        use="optional"
+                        default="true" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="cameraTarget" type="tns:PosWithInterpolation" >
+        <xsd:annotation>
+            <xsd:documentation>
+                camera target.
+            </xsd:documentation>
+        </xsd:annotation>
+
+    </xsd:element>
+
+
+    <xsd:element name="cameraRotation" >
+        <xsd:annotation>
+            <xsd:documentation>
+                camera-rotation around camera-target
+                  with polar-coordinates parameters.
+
+                xRad = -radian(UI_X) [latitude]
+                yRad =  radian(UI_Y) [longitude]
+                zRad =  radian(UI_Z) [roll]
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:InterpolationSingle" >
+                    <xsd:attribute name="xRad" type="xsd:float" use="required" />
+                    <xsd:attribute name="yRad" type="xsd:float" use="required" />
+                    <xsd:attribute name="zRad" type="xsd:float" use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="cameraRange" >
+        <xsd:annotation>
+            <xsd:documentation>
+                camera range.
+                sign was negated from UI_RANGE.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:InterpolationSingle" >
+                    <xsd:attribute
+                        name="range"
+                        type="xsd:float"
+                        use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="projection" >
+        <xsd:annotation>
+            <xsd:documentation>
+                projection data.
+                vertDeg : vertical screen-projection angle by degree.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:InterpolationSingle" >
+                    <xsd:attribute
+                        name="vertDeg"
+                        type="tns:ProjectionAngle"
+                        use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="luminousSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                luminous sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:luminousAct"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="LuminousFrameNo" >
+            <xsd:selector xpath="./tns:luminousAct" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="luminousAct" >
+        <xsd:annotation>
+            <xsd:documentation>
+                luminous data.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:sequence>
+                        <xsd:element ref="tns:lumiColor" />
+                        <xsd:element ref="tns:lumiDirection" />
+                    </xsd:sequence>
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="lumiColor" >
+        <xsd:annotation>
+            <xsd:documentation>
+                luminous color by RGB color space.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:attribute
+                name="rCol"
+                type="tns:ColorComponent"
+                use="required" />
+            <xsd:attribute
+                name="gCol"
+                type="tns:ColorComponent"
+                use="required" />
+            <xsd:attribute
+                name="bCol"
+                type="tns:ColorComponent"
+                use="required" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="lumiDirection" >
+        <xsd:annotation>
+            <xsd:documentation>
+                luminous direction by vector.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:attribute
+                name="xVec"
+                type="tns:DirVecComponent"
+                use="required" />
+            <xsd:attribute
+                name="yVec"
+                type="tns:DirVecComponent"
+                use="required" />
+            <xsd:attribute
+                name="zVec"
+                type="tns:DirVecComponent"
+                use="required" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="shadowSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                shadow sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:shadowAct"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="ShadowFrameNo" >
+            <xsd:selector xpath="./tns:shadowAct" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="shadowAct" >
+        <xsd:annotation>
+            <xsd:documentation>
+                shadow data.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:attribute
+                        name="mode"
+                        type="tns:ShadowType"
+                        use="required" />
+                    <xsd:attribute
+                        name="rawParam"
+                        type="tns:ShadowRawParam"
+                        use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+    <xsd:element name="flagSequence" >
+        <xsd:annotation>
+            <xsd:documentation>
+                numbered flag sequence.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:sequence>
+                <xsd:element
+                    ref="tns:flagMotion"
+                    minOccurs="0" maxOccurs="unbounded" />
+            </xsd:sequence>
+        </xsd:complexType>
+
+        <xsd:unique name="FlagFrameNo" >
+            <xsd:selector xpath="./tns:flagMotion" />
+            <xsd:field xpath="@frame" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="flagMotion" >
+        <xsd:annotation>
+            <xsd:documentation>
+                numbered motion flags.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:complexContent>
+                <xsd:extension base="tns:FrameNumbered" >
+                    <xsd:sequence>
+                        <xsd:element
+                            ref="tns:ikSwitch"
+                            minOccurs="0" maxOccurs="unbounded" />
+                    </xsd:sequence>
+                    <xsd:attribute
+                        name="showModel"
+                        type="xsd:boolean"
+                        use="required" />
+                </xsd:extension>
+            </xsd:complexContent>
+        </xsd:complexType>
+
+        <xsd:unique name="IkBoneName" >
+            <xsd:selector xpath="./tns:ikSwitch" />
+            <xsd:field xpath="@name" />
+        </xsd:unique>
+
+    </xsd:element>
+
+
+    <xsd:element name="ikSwitch" >
+        <xsd:annotation>
+            <xsd:documentation>
+                IK ON/OFF switch for each IK-Bone.
+            </xsd:documentation>
+        </xsd:annotation>
+
+        <xsd:complexType>
+            <xsd:attribute
+                name="name"
+                type="xsd:string"
+                use="required" />
+            <xsd:attribute
+                name="valid"
+                type="xsd:boolean"
+                use="required" />
+        </xsd:complexType>
+
+    </xsd:element>
+
+
+</xsd:schema>
+
+
+<!-- EOF -->
index 796bf90..eabbdc5 100644 (file)
@@ -395,7 +395,7 @@ public class VmdMotionTest {
 
         assertEquals(
                 "model name : カメラ・照明\n"
-                +"bone#0 morph#0 camera#0 luminous#0 shadow#0",
+                +"bone#0 morph#0 camera#0 luminous#0 shadow#0 flag#0",
                 motion.toString());
 
         motion.setModelName("model");
@@ -414,10 +414,15 @@ public class VmdMotionTest {
         motion.getShadowMotionList().add(new ShadowMotion());
         motion.getShadowMotionList().add(new ShadowMotion());
         motion.getShadowMotionList().add(new ShadowMotion());
+        motion.getNumberedFlagList().add(new NumberedVmdFlag());
+        motion.getNumberedFlagList().add(new NumberedVmdFlag());
+        motion.getNumberedFlagList().add(new NumberedVmdFlag());
+        motion.getNumberedFlagList().add(new NumberedVmdFlag());
+        motion.getNumberedFlagList().add(new NumberedVmdFlag());
 
         assertEquals(
                 "model name : model\n"
-                +"bone#1 morph#2 camera#3 luminous#4 shadow#5",
+                +"bone#1 morph#2 camera#3 luminous#4 shadow#5 flag#5",
                 motion.toString());
 
         return;
diff --git a/src/test/resources/testdata/vmd130609/minimum/minmotion.xml b/src/test/resources/testdata/vmd130609/minimum/minmotion.xml
new file mode 100644 (file)
index 0000000..1deeea6
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+  MikuMikuDance
+    motion-data(*.vmd) on XML
+-->
+
+
+<vmdMotion
+  xmlns="http://mikutoga.sourceforge.jp/xml/ns/vmdxml/130609A"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://mikutoga.sourceforge.jp/xml/ns/vmdxml/130609A
+    http://mikutoga.sourceforge.jp/xml/xsd/vmdxml-130609A.xsd"
+  version="130609A"
+>
+
+<!-- [NAMELESS] -->
+<modelName name="" />
+
+<boneMotionSequence>
+</boneMotionSequence>
+
+<morphSequence>
+</morphSequence>
+
+<flagSequence>
+</flagSequence>
+
+</vmdMotion>
+
+<!-- EOF -->
diff --git a/src/test/resources/testdata/vmd130609/small/onlyFlag.xml b/src/test/resources/testdata/vmd130609/small/onlyFlag.xml
new file mode 100644 (file)
index 0000000..f880cee
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!--
+  MikuMikuDance
+    motion-data(*.vmd) on XML
+-->
+
+
+<vmdMotion
+  xmlns="http://mikutoga.sourceforge.jp/xml/ns/vmdxml/130609A"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://mikutoga.sourceforge.jp/xml/ns/vmdxml/130609A
+    http://mikutoga.sourceforge.jp/xml/xsd/vmdxml-130609A.xsd"
+  version="130609A"
+>
+
+<!-- [NAMELESS] -->
+<modelName name="" />
+
+<boneMotionSequence>
+</boneMotionSequence>
+
+<morphSequence>
+</morphSequence>
+
+<flagSequence>
+    <flagMotion frame="9" showModel="true" />
+    <flagMotion frame="99" showModel="false">
+        <ikSwitch name="IKBONE1" valid="true" />
+        <ikSwitch name="IKBONE2" valid="false" />
+    </flagMotion>
+</flagSequence>
+
+</vmdMotion>
+
+<!-- EOF -->