From: Olyutorskii Date: Sat, 8 Jun 2013 04:30:29 +0000 (+0900) Subject: SAX対応 X-Git-Tag: fromMercurial~5 X-Git-Url: http://git.osdn.net/view?p=mikutoga%2FPmd2XML.git;a=commitdiff_plain;h=b12782f3ce4b78faa618062b553cca3db556b406;ds=sidebyside SAX対応 --- diff --git a/pom.xml b/pom.xml index c867323..643fea3 100644 --- a/pom.xml +++ b/pom.xml @@ -112,7 +112,7 @@ jp.sourceforge.mikutoga togagem - 2.102.5-SNAPSHOT + 3.101.5-SNAPSHOT compile @@ -129,7 +129,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 1.2 + 1.3.1 @@ -145,7 +145,7 @@ org.apache.maven.plugins maven-install-plugin - 2.4 + 2.5.1 @@ -270,7 +270,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.14.1 + 2.16 false true @@ -292,7 +292,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 2.10 + 2.11 @@ -424,7 +424,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.9 + 2.9.1 false true @@ -453,7 +453,7 @@ org.apache.maven.plugins maven-surefire-report-plugin - 2.14.1 + 2.16 false @@ -482,7 +482,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 2.10 + 2.11 false diff --git a/src/main/config/checks.xml b/src/main/config/checks.xml index 3d6d80e..3e31cbb 100644 --- a/src/main/config/checks.xml +++ b/src/main/config/checks.xml @@ -375,10 +375,6 @@ --> - - diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/RigidGroup.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/RigidGroup.java index 7399b4a..0aaee86 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/model/RigidGroup.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/RigidGroup.java @@ -17,6 +17,9 @@ import java.util.List; */ public class RigidGroup implements SerialNumbered, Iterable { + public static final int MAX_RIGID_GROUP = 16; + + private final List rigidList = new ArrayList(); private int serialNo = -1; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/ToonMap.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/ToonMap.java index d809a58..37f928a 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/model/ToonMap.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/ToonMap.java @@ -25,6 +25,7 @@ import java.util.TreeMap; */ public class ToonMap { + public static final int MAX_CUSTOM_TOON = 10; private static final Map DEF_TOONMAP; static{ @@ -43,6 +44,8 @@ public class ToonMap { map.put(0xff, "toon0.bmp"); DEF_TOONMAP = Collections.unmodifiableMap(map); + + assert DEF_TOONMAP.size() == MAX_CUSTOM_TOON + 1; } private final Map toonMap = @@ -85,8 +88,8 @@ public class ToonMap { * @return 等しければtrue */ public boolean isDefaultMap(){ - if(this.toonMap.equals(DEF_TOONMAP)) return true; - return false; + boolean result = this.toonMap.equals(DEF_TOONMAP); + return result; } /** @@ -99,9 +102,10 @@ public class ToonMap { if(thisToon == null) return false; String defToon = DEF_TOONMAP.get(idx); - if(thisToon.equals(defToon)) return true; - return false; + boolean result = thisToon.equals(defToon); + + return result; } /** diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/BoneBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/BoneBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/BoneBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/BoneBuilder.java index c3b1b65..07d3b03 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/BoneBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/BoneBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.Iterator; import java.util.LinkedList; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/JointBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/JointBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/JointBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/JointBuilder.java index 3e3a8ca..c04c399 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/JointBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/JointBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.Iterator; import java.util.List; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/MaterialBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MaterialBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/MaterialBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MaterialBuilder.java index c075436..959496b 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/MaterialBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MaterialBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.awt.Color; import java.util.Iterator; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/MorphBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MorphBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/MorphBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MorphBuilder.java index db02712..64b5e14 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/MorphBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/MorphBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.ArrayList; import java.util.Iterator; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporter.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporter.java similarity index 94% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporter.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporter.java index da633fd..fef1a3d 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporter.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporter.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.io.OutputStream; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterBase.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterBase.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterBase.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterBase.java index f8ae602..7553194 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterBase.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterBase.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.awt.Color; import java.io.IOException; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt1.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt1.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt1.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt1.java index 5de6fb6..c5ae1ac 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt1.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt1.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt2.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt2.java similarity index 98% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt2.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt2.java index e40fd4a..ede02ae 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt2.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt2.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt3.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt3.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt3.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt3.java index 20ae6fb..01af3ac 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdExporterExt3.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdExporterExt3.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdLoader.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdLoader.java similarity index 98% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdLoader.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdLoader.java index 9b25ff4..7c3c561 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/PmdLoader.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/PmdLoader.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/RigidBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/RigidBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/RigidBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/RigidBuilder.java index 7f1e9da..3c00302 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/RigidBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/RigidBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.Iterator; import java.util.List; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/ShapeBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ShapeBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/ShapeBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ShapeBuilder.java index 3896b13..a7321ff 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/ShapeBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ShapeBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.Iterator; import java.util.List; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/TextBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/TextBuilder.java similarity index 99% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/TextBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/TextBuilder.java index 5395fff..6851f17 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/TextBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/TextBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import java.util.Iterator; import java.util.List; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/ToonBuilder.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ToonBuilder.java similarity index 97% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/ToonBuilder.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ToonBuilder.java index 51d4b65..da8f9ee 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/ToonBuilder.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/ToonBuilder.java @@ -5,7 +5,7 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; import jp.sfjp.mikutoga.bin.parser.ParseStage; import jp.sfjp.mikutoga.pmd.PmdConst; diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/binio/package-info.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/package-info.java similarity index 81% rename from src/main/java/jp/sfjp/mikutoga/pmd/binio/package-info.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/binio/package-info.java index 3bba63b..39e2514 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/binio/package-info.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/binio/package-info.java @@ -9,6 +9,6 @@ * PMDモデルファイル(*.pmd)用入出力。 */ -package jp.sfjp.mikutoga.pmd.binio; +package jp.sfjp.mikutoga.pmd.model.binio; /* EOF */ diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/CloseXmlMark.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/CloseXmlMark.java new file mode 100644 index 0000000..09a9023 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/CloseXmlMark.java @@ -0,0 +1,23 @@ +/* + * annotation for ending XML-element + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * XML要素終了通知用注釈。 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@interface CloseXmlMark { + /** タグ指定。 */ + PmdTag value(); +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterBone.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterBone.java new file mode 100644 index 0000000..8dce9ea --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterBone.java @@ -0,0 +1,373 @@ +/* + * bone xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.BoneType; +import jp.sfjp.mikutoga.pmd.model.BoneGroup; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.IKChain; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; + +/** + * ボーン設定のXMLエクスポーター。 + */ +class ExporterBone extends ProxyXmlExporter { + + private static final Locale DEF_LOCALE = Locale.JAPANESE; + + private static final String LEAD_REF = "Ref:"; + private static final String BONETYPE_COMMENT = + "Bone types:\n" + + "[0 : ROTATE : Rotate : 回転 :]\n" + + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n" + + "[2 : IK : IK : IK :]\n" + + "[3 : UNKNOWN : Unknown : 不明 :]\n" + + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n" + + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n" + + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n" + + "[7 : HIDDEN : Hidden : 非表示 :]\n" + + "[8 : TWIST : Twist : 捩り :]\n" + + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n"; + + + private final ExtraExporter exp; + private XmlModelFileType xmlType = XmlModelFileType.XML_130128; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExporterBone(PmdXmlExporter delegate) { + super(delegate); + this.exp = new ExtraExporter(delegate); + return; + } + + /** + * 出力XMLファイル種別を設定する。 + * @param type ファイル種別 + */ + void setXmlFileType(XmlModelFileType type){ + this.xmlType = type; + return; + } + + /** + * ボーンリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putBoneList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.BONE_LIST.tag()).ln(); + pushNest(); + + boolean dumped = false; + for(BoneInfo bone : model.getBoneList()){ + if( ! dumped ){ + ln().putBlockComment(BONETYPE_COMMENT).ln(); + } + putBone(bone); + dumped = true; + } + + popNest(); + ind().putETag(PmdTag.BONE_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のボーン情報を出力する。 + * @param bone ボーン情報 + * @throws IOException 出力エラー + */ + private void putBone(BoneInfo bone) + throws IOException{ + putBoneComment(bone); + + ind().putOpenSTag(PmdTag.BONE.tag()).sp(); + I18nText i18nName = bone.getBoneName(); + this.exp.putPrimaryNameAttr(PmdAttr.NAME, i18nName); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_ID, + ExtraExporter.PFX_BONE, bone); + sp(); + BoneType type = bone.getBoneType(); + putAttr(PmdAttr.TYPE.attr(), type.name()); + sp().putCloseSTag().ln(); + pushNest(); + + this.exp.putI18nName(i18nName); + + MkPos3D position = bone.getPosition(); + ind(); + this.exp.putPosition(position); + ln(); + + BoneInfo srcBone = bone.getSrcBone(); + if(bone.getBoneType() == BoneType.LINKEDROT){ + putRotationRatio(bone); + }else if(srcBone != null){ + putSourceBone(srcBone); + } + + BoneInfo prev = bone.getPrevBone(); + BoneInfo next = bone.getNextBone(); + putBoneChain(prev, next); + + popNest(); + ind().putETag(PmdTag.BONE.tag()).ln(2); + + return; + } + + /** + * ボーンコメントを出力する。 + * @param bone ボーン + * @throws IOException 出力エラー + */ + private void putBoneComment(BoneInfo bone) + throws IOException{ + StringBuilder boneComment = new StringBuilder(); + + I18nText i18nName = bone.getBoneName(); + String boneName = i18nName.getText(); + if(boneName.isEmpty()){ + boneName = "[NAMELESS]"; + } + boneComment.append(boneName); + + BoneType type = bone.getBoneType(); + String typeName = type.getGuiName(DEF_LOCALE); + boneComment.append("\u0020[").append(typeName).append(']'); + ind().putLineComment(boneComment.toString()).ln(); + + return; + } + + /** + * ボーン回転連動率を出力する。 + * @param bone ボーン + * @throws IOException 出力エラー + */ + private void putRotationRatio(BoneInfo bone) + throws IOException{ + ind().putOpenSTag(PmdTag.ROTATION_RATIO.tag()).sp(); + putIntAttr(PmdAttr.RATIO.attr(), + bone.getRotationRatio()).sp(); + putCloseEmpty().ln(); + + return; + } + + /** + * 元ボーン情報を出力する。 + * @param source 元ボーン + * @throws IOException 出力エラー + */ + private void putSourceBone(BoneInfo source) + throws IOException{ + + + String iktag; + switch(this.xmlType){ + case XML_101009: + iktag = PmdTag.IK_BONE.tag(); + break; + case XML_130128: + iktag = PmdTag.SOURCE_BONE.tag(); + break; + default: + assert false; + throw new AssertionError(); + } + + ind().putOpenSTag(iktag).sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF, + ExtraExporter.PFX_BONE, source); + sp(); + putCloseEmpty().sp(); + + String ikBoneName = LEAD_REF + source.getBoneName().getText(); + putLineComment(ikBoneName); + ln(); + + return; + } + + /** + * ボーン間チェーン情報を出力する。 + * @param prev 前ボーン + * @param next 次ボーン + * @throws IOException 出力エラー + */ + private void putBoneChain(BoneInfo prev, BoneInfo next) + throws IOException{ + StringBuilder chainComment = new StringBuilder(); + + if(prev != null){ + chainComment.append('[') + .append(prev.getBoneName().getPrimaryText()) + .append("]\u0020>>#"); + } + if(next != null){ + if(chainComment.length() <= 0) chainComment.append('#'); + chainComment.append(">>\u0020[") + .append(next.getBoneName().getPrimaryText()) + .append(']'); + } + if(chainComment.length() > 0){ + ln(); + ind().putLineComment(chainComment).ln(); + } + + ind().putOpenSTag(PmdTag.BONE_CHAIN.tag()); + if(prev != null){ + sp(); + this.exp.putNumberedIdAttr(PmdAttr.PREV_BONE_IDREF, + ExtraExporter.PFX_BONE, prev); + } + if(next != null){ + sp(); + this.exp.putNumberedIdAttr(PmdAttr.NEXT_BONE_IDREF, + ExtraExporter.PFX_BONE, next); + } + sp().putCloseEmpty().ln(); + + return; + } + + /** + * ボーングループリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putBoneGroupList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.BONE_GROUP_LIST.tag()).ln(); + + pushNest(); + boolean dumped = false; + List groupList = model.getBoneGroupList(); + for(BoneGroup group : groupList){ + if(group.isDefaultBoneGroup()) continue; + if( ! dumped ) ln(); + putBoneGroup(group); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.BONE_GROUP_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のボーングループ情報を出力する。 + * @param group ボーングループ情報 + * @throws IOException 出力エラー + */ + private void putBoneGroup(BoneGroup group) + throws IOException{ + I18nText i18nName = group.getGroupName(); + + this.exp.putLocalNameComment(i18nName); + ln(); + ind().putOpenSTag(PmdTag.BONE_GROUP.tag()).sp(); + this.exp.putPrimaryNameAttr(PmdAttr.NAME, i18nName); + sp().putCloseSTag().ln(); + pushNest(); + + this.exp.putI18nName(i18nName); + + for(BoneInfo bone : group){ + ind().putOpenSTag(PmdTag.BONE_GROUP_MEMBER.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF, + ExtraExporter.PFX_BONE, bone); + sp(); + putCloseEmpty().sp(); + String boneName = LEAD_REF + bone.getBoneName().getText(); + putLineComment(boneName).ln(); + } + + popNest(); + ind().putETag(PmdTag.BONE_GROUP.tag()).ln(2); + + return; + } + + /** + * IKチェーンリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putIKChainList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.IK_CHAIN_LIST.tag()).ln(); + + pushNest(); + boolean dumped = false; + List chainList = model.getIKChainList(); + for(IKChain chain : chainList){ + if( ! dumped ) ln(); + putIKChain(chain); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.IK_CHAIN_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のIKチェーン情報を出力する。 + * @param chain チェーン情報 + * @throws IOException 出力エラー + */ + private void putIKChain(IKChain chain) + throws IOException{ + int depth = chain.getIKDepth(); + float weight = chain.getIKWeight(); + BoneInfo ikBone = chain.getIkBone(); + + ind().putLineComment(LEAD_REF + ikBone.getBoneName().getText()).ln(); + ind().putOpenSTag(PmdTag.IK_CHAIN.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.IK_BONE_IDREF, + ExtraExporter.PFX_BONE, ikBone); + sp(); + putIntAttr(PmdAttr.RECURSIVE_DEPTH.attr(), depth).sp(); + putFloatAttr(PmdAttr.WEIGHT.attr(), weight); + sp().putCloseSTag().ln(); + pushNest(); + + for(BoneInfo bone : chain){ + ind().putOpenSTag(PmdTag.CHAIN_ORDER.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF, + ExtraExporter.PFX_BONE, bone); + sp(); + putCloseEmpty().sp(); + putLineComment(LEAD_REF + bone.getBoneName().getText()); + ln(); + } + + popNest(); + ind().putETag(PmdTag.IK_CHAIN.tag()).ln(2); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterDynamics.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterDynamics.java new file mode 100644 index 0000000..8ca5534 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterDynamics.java @@ -0,0 +1,460 @@ +/* + * dynamics xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.Deg3d; +import jp.sfjp.mikutoga.pmd.Rad3d; +import jp.sfjp.mikutoga.pmd.RigidShapeType; +import jp.sfjp.mikutoga.pmd.TripletRange; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.DynamicsInfo; +import jp.sfjp.mikutoga.pmd.model.JointInfo; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.pmd.model.RigidGroup; +import jp.sfjp.mikutoga.pmd.model.RigidInfo; +import jp.sfjp.mikutoga.pmd.model.RigidShape; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; + +/** + * 剛体力学設定のXMLエクスポーター。 + */ +class ExporterDynamics extends ProxyXmlExporter { + + private static final String LEAD_REF = "Ref:"; + private static final String RIGIDBEHAVIOR_COMMENT = + "Rigid behavior types:\n" + + "[0 : FOLLOWBONE : ボーン追従 ]\n" + + "[1 : ONLYDYNAMICS : 物理演算 ]\n" + + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n"; + + + private final ExtraExporter exp; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExporterDynamics(PmdXmlExporter delegate) { + super(delegate); + this.exp = new ExtraExporter(delegate); + return; + } + + /** + * 剛体リストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putRigidList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.RIGID_LIST.tag()).ln(); + pushNest(); + + boolean dumped = false; + for(RigidInfo rigid : model.getRigidList()){ + if( ! dumped ){ + ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln(); + } + putRigid(rigid); + dumped = true; + } + + popNest(); + ind().putETag(PmdTag.RIGID_LIST.tag()).ln(2); + + return; + } + + /** + * 個別の剛体情報を出力する。 + * @param rigid 剛体情報 + * @throws IOException 出力エラー + */ + private void putRigid(RigidInfo rigid) throws IOException{ + I18nText i18nName = rigid.getRigidName(); + String primary = i18nName.getPrimaryText(); + + this.exp.putLocalNameComment(i18nName); + ln(); + + ind().putOpenSTag(PmdTag.RIGID.tag()).sp(); + putAttr(PmdAttr.NAME.attr(), primary).sp(); + this.exp.putNumberedIdAttr(PmdAttr.RIGID_ID, + ExtraExporter.PFX_RIGID, rigid); + sp(); + putAttr(PmdAttr.BEHAVIOR.attr(), + rigid.getBehaviorType().name()); + sp().putCloseSTag().ln(); + pushNest(); + + this.exp.putI18nName(i18nName); + putRigidBody(rigid); + + popNest(); + ind().putETag(PmdTag.RIGID.tag()).ln(2); + + return; + } + + /** + * 剛体の詳細を出力する。 + * @param rigid 剛体情報 + * @throws IOException 出力エラー + */ + private void putRigidBody(RigidInfo rigid) throws IOException{ + BoneInfo linkedBone = rigid.getLinkedBone(); + putLinkedBone(linkedBone); + + RigidShape shape = rigid.getRigidShape(); + putRigidShape(shape); + + MkPos3D position = rigid.getPosition(); + ind(); + this.exp.putPosition(position); + ln(); + + Rad3d rotation = rigid.getRotation(); + ind(); + this.exp.putRadRotation(rotation); + ln(); + + DynamicsInfo dynamics = rigid.getDynamicsInfo(); + putDynamics(dynamics); + ln(); + + Collection throughGroup = rigid.getThroughGroupColl(); + putThroughRigid(throughGroup); + + return; + } + + /** + * 剛体接続ボーンを出力する。 + * @param linkedBone 接続ボーン + * @throws IOException 出力エラー + */ + private void putLinkedBone(BoneInfo linkedBone) throws IOException{ + if(linkedBone == null) return; + + ind().putOpenSTag(PmdTag.LINKED_BONE.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF, + ExtraExporter.PFX_BONE, + linkedBone); + sp(); + putCloseEmpty(); + sp().putLineComment(LEAD_REF + linkedBone.getBoneName().getText()); + ln(2); + + return; + } + + /** + * 剛体形状を出力する。 + * @param shape 剛体形状 + * @throws IOException 出力エラー + */ + private void putRigidShape(RigidShape shape) throws IOException{ + RigidShapeType type = shape.getShapeType(); + + switch(type){ + case BOX: + ind().putOpenSTag(PmdTag.RIGID_SHAPE_BOX.tag()).sp(); + putFloatAttr(PmdAttr.WIDTH.attr(), + shape.getWidth()).sp(); + putFloatAttr(PmdAttr.HEIGHT.attr(), + shape.getHeight()).sp(); + putFloatAttr(PmdAttr.DEPTH.attr(), + shape.getDepth()).sp(); + break; + case SPHERE: + ind().putOpenSTag(PmdTag.RIGID_SHAPE_SPHERE.tag()).sp(); + putFloatAttr(PmdAttr.RADIUS.attr(), + shape.getRadius()).sp(); + break; + case CAPSULE: + ind().putOpenSTag(PmdTag.RIGID_SHAPE_CAPSULE.tag()).sp(); + putFloatAttr(PmdAttr.HEIGHT.attr(), + shape.getHeight()).sp(); + putFloatAttr(PmdAttr.RADIUS.attr(), + shape.getRadius()).sp(); + break; + default: + assert false; + throw new AssertionError(); + } + + putCloseEmpty().ln(); + + return; + } + + /** + * 力学設定を出力する。 + * @param dynamics 力学設定 + * @throws IOException 出力エラー + */ + private void putDynamics(DynamicsInfo dynamics) + throws IOException{ + ind().putOpenSTag(PmdTag.DYNAMICS.tag()).ln(); + pushNest(); + ind().putFloatAttr(PmdAttr.MASS.attr(), + dynamics.getMass()).ln(); + ind().putFloatAttr(PmdAttr.DAMPING_POSITION.attr(), + dynamics.getDampingPosition()).ln(); + ind().putFloatAttr(PmdAttr.DAMPING_ROTATION.attr(), + dynamics.getDampingRotation()).ln(); + ind().putFloatAttr(PmdAttr.RESTITUTION.attr(), + dynamics.getRestitution()).ln(); + ind().putFloatAttr(PmdAttr.FRICTION.attr(), + dynamics.getFriction()).ln(); + popNest(); + ind().putCloseEmpty().ln(); + + return; + } + + /** + * 通過剛体グループを出力する。 + * @param groupColl 通過剛体グループ群 + * @throws IOException 出力エラー + */ + private void putThroughRigid(Collection groupColl) + throws IOException{ + for(RigidGroup group : groupColl){ + ind().putOpenSTag(PmdTag.THROUGH_RIGID_GROUP.tag()).sp(); + this.exp + .putNumberedIdAttr(PmdAttr.RIGID_GROUP_IDREF, + ExtraExporter.PFX_RIGIDGROUP, + group.getSerialNumber() + 1); + sp(); + putCloseEmpty().ln(); + } + + return; + } + + /** + * 剛体グループリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putRigidGroupList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.RIGID_GROUP_LIST.tag()).ln(2); + pushNest(); + + boolean singleLast = false; + for(RigidGroup group : model.getRigidGroupList()){ + List rigidList = group.getRigidList(); + if(singleLast && ! rigidList.isEmpty()){ + ln(); + } + ind().putOpenSTag(PmdTag.RIGID_GROUP.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.RIGID_GROUP_ID, + ExtraExporter.PFX_RIGIDGROUP, + group.getSerialNumber() + 1); + sp(); + if(rigidList.isEmpty()){ + putCloseEmpty().ln(); + singleLast = true; + continue; + } + putCloseSTag().ln(); + pushNest(); + + for(RigidInfo rigid : rigidList){ + ind().putOpenSTag(PmdTag.RIGID_GROUP_MEMBER.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.RIGID_IDREF, + ExtraExporter.PFX_RIGID, rigid); + sp(); + putCloseEmpty(); + sp(); + putLineComment(LEAD_REF + rigid.getRigidName().getText()); + ln(); + } + + popNest(); + ind().putETag(PmdTag.RIGID_GROUP.tag()).ln(2); + singleLast = false; + } + + if(singleLast){ + ln(); + } + + popNest(); + ind().putETag(PmdTag.RIGID_GROUP_LIST.tag()).ln(2); + + return; + } + + /** + * ジョイントリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putJointList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.JOINT_LIST.tag()).ln(); + + pushNest(); + boolean dumped = false; + List jointList = model.getJointList(); + for(JointInfo joint : jointList){ + if( ! dumped ) ln(); + putJoint(joint); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.JOINT_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のジョイント情報を出力する。 + * @param joint ジョイント情報 + * @throws IOException 出力エラー + */ + private void putJoint(JointInfo joint) + throws IOException{ + I18nText i18nName = joint.getJointName(); + + this.exp.putLocalNameComment(i18nName); + ln(); + ind().putOpenSTag(PmdTag.JOINT.tag()).sp(); + this.exp.putPrimaryNameAttr(PmdAttr.NAME, i18nName); + sp().putCloseSTag().ln(); + pushNest(); + + this.exp.putI18nName(i18nName); + + RigidInfo rigidA = joint.getRigidA(); + RigidInfo rigidB = joint.getRigidB(); + + ind(); + putLineComment( + "[" + + rigidA.getRigidName().getText() + + "]\u0020<=>\u0020[" + + rigidB.getRigidName().getText() + + "]"); + ln(); + + ind().putOpenSTag(PmdTag.JOINTED_RIGID_PAIR.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.RIGID_IDREF_1, + ExtraExporter.PFX_RIGID, rigidA); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.RIGID_IDREF_2, + ExtraExporter.PFX_RIGID, rigidB); + sp(); + putCloseEmpty().ln(2); + + putJointLimit(joint); + putJointElastic(joint); + + popNest(); + ind().putETag(PmdTag.JOINT.tag()).ln(2); + + return; + } + + /** + * ジョイント制限情報を出力する。 + * @param joint ジョイント情報 + * @throws IOException 出力エラー + */ + private void putJointLimit(JointInfo joint) + throws IOException{ + MkPos3D position = joint.getPosition(); + ind(); + this.exp.putPosition(position); + ln(); + + ind().putOpenSTag(PmdTag.LIMIT_POSITION.tag()).ln(); + pushNest(); + TripletRange posRange = joint.getPositionRange(); + putTripletRangeAttr(posRange); + popNest(); + ind().putCloseEmpty().ln(2); + + Rad3d rotation = joint.getRotation(); + ind(); + this.exp.putRadRotation(rotation); + ln(); + + ind().putOpenSTag(PmdTag.LIMIT_ROTATION.tag()).ln(); + pushNest(); + TripletRange rotRange = joint.getRotationRange(); + putTripletRangeAttr(rotRange); + popNest(); + ind().putCloseEmpty().ln(2); + + return; + } + + /** + * XYZ範囲属性を出力する。 + * @param range XYZ範囲 + * @throws IOException 出力エラー + */ + private void putTripletRangeAttr(TripletRange range) + throws IOException{ + ind(); + putFloatAttr(PmdAttr.X_FROM.attr(), range.getXFrom()).sp(); + putFloatAttr(PmdAttr.X_TO.attr(), range.getXTo() ).ln(); + + ind(); + putFloatAttr(PmdAttr.Y_FROM.attr(), range.getYFrom()).sp(); + putFloatAttr(PmdAttr.Y_TO.attr(), range.getYTo() ).ln(); + + ind(); + putFloatAttr(PmdAttr.Z_FROM.attr(), range.getZFrom()).sp(); + putFloatAttr(PmdAttr.Z_TO.attr(), range.getZTo() ).ln(); + + return; + } + + /** + * ジョイント弾性情報を出力する。 + * @param joint ジョイント情報 + * @throws IOException 出力エラー + */ + private void putJointElastic(JointInfo joint) + throws IOException{ + ind().putOpenSTag(PmdTag.ELASTIC_POSITION.tag()).sp(); + MkPos3D elaPosition = joint.getElasticPosition(); + putFloatAttr(PmdAttr.X.attr(), + (float) elaPosition.getXpos()).sp(); + putFloatAttr(PmdAttr.Y.attr(), + (float) elaPosition.getYpos()).sp(); + putFloatAttr(PmdAttr.Z.attr(), + (float) elaPosition.getZpos()).sp(); + putCloseEmpty().ln(); + + ind().putOpenSTag(PmdTag.ELASTIC_ROTATION.tag()).sp(); + Deg3d elaRotation = joint.getElasticRotation(); + putFloatAttr(PmdAttr.X_DEG.attr(), + elaRotation.getXDeg()).sp(); + putFloatAttr(PmdAttr.Y_DEG.attr(), + elaRotation.getYDeg()).sp(); + putFloatAttr(PmdAttr.Z_DEG.attr(), + elaRotation.getZDeg()).sp(); + putCloseEmpty().ln(2); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMaterial.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMaterial.java new file mode 100644 index 0000000..92b759e --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMaterial.java @@ -0,0 +1,258 @@ +/* + * material xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.awt.Color; +import java.io.IOException; +import java.util.List; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.pmd.model.Material; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.pmd.model.ShadeInfo; +import jp.sfjp.mikutoga.pmd.model.ToonMap; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; + +/** + * マテリアル設定のXMLエクスポーター。 + */ +class ExporterMaterial extends ProxyXmlExporter { + + // sRGBカラー情報配列インデックス + private static final int IDX_RED = 0; + private static final int IDX_GREEN = 1; + private static final int IDX_BLUE = 2; + private static final int IDX_ALPHA = 3; + + + private final ExtraExporter exp; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExporterMaterial(PmdXmlExporter delegate) { + super(delegate); + this.exp = new ExtraExporter(delegate); + return; + } + + /** + * マテリアル素材一覧を出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putMaterialList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.MATERIAL_LIST.tag()).ln(); + + pushNest(); + int ct = 0; + boolean dumped = false; + List materialList = model.getMaterialList(); + for(Material material : materialList){ + if( ! dumped ) ln(); + putMaterial(material, ct++); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.MATERIAL_LIST.tag()).ln(2); + + return; + } + + /** + * マテリアル素材情報を出力する。 + * @param material マテリアル素材 + * @param no マテリアル通し番号 + * @throws IOException 出力エラー + */ + private void putMaterial(Material material, int no) + throws IOException{ + I18nText name = material.getMaterialName(); + String primary = name.getPrimaryText(); + String local = name.getText(); + if(local != null && local.length() > 0){ + ind().putLineComment(local).ln(); + } + + ind().putOpenSTag(PmdTag.MATERIAL.tag()).sp(); + if(primary != null && primary.length() > 0){ + putAttr(PmdAttr.NAME.attr(), primary).sp(); + } + String bool; + if(material.getEdgeAppearance()) bool = "true"; + else bool = "false"; + putAttr(PmdAttr.SHOW_EDGE.attr(), bool); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.SURFACE_GROUP_IDREF, + ExtraExporter.PFX_SURFACEGROUP, no); + sp().putCloseSTag().ln(); + pushNest(); + + this.exp.putI18nName(name); + + putPhongShade(material); + + ShadeInfo shade = material.getShadeInfo(); + + if(shade.isValidToonIndex()){ + putToon(shade); + } + + putShadeFile(shade); + + popNest(); + ind().putETag(PmdTag.MATERIAL.tag()).ln(2); + + return; + } + + /** + * フォンシェーディング情報を出力する。 + * @param material マテリアル + * @throws IOException 出力エラー + */ + private void putPhongShade(Material material) + throws IOException{ + float[] rgba = null; + + ind().putOpenSTag(PmdTag.DIFFUSE.tag()).sp(); + Color diffuse = material.getDiffuseColor(); + rgba = diffuse.getRGBComponents(rgba); + putTriColor(rgba); + putFloatAttr(PmdAttr.ALPHA.attr(), rgba[IDX_ALPHA]).sp(); + putCloseEmpty().ln(); + + float shininess = material.getShininess(); + ind().putOpenSTag(PmdTag.SPECULAR.tag()).sp(); + Color specular = material.getSpecularColor(); + rgba = specular.getRGBComponents(rgba); + putTriColor(rgba); + putFloatAttr(PmdAttr.SHININESS.attr(), shininess).sp(); + putCloseEmpty().ln(); + + ind().putOpenSTag(PmdTag.AMBIENT.tag()).sp(); + Color ambient = material.getAmbientColor(); + rgba = ambient.getRGBComponents(rgba); + putTriColor(rgba); + putCloseEmpty().ln(); + + return; + } + + /** + * 三原色属性を出力する。 + * @param rgb カラー情報 + * @throws IOException 出力エラー + */ + private void putTriColor(float[] rgb) + throws IOException{ + putFloatAttr(PmdAttr.R.attr(), rgb[IDX_RED] ).sp(); + putFloatAttr(PmdAttr.G.attr(), rgb[IDX_GREEN]).sp(); + putFloatAttr(PmdAttr.B.attr(), rgb[IDX_BLUE] ).sp(); + + return; + } + + /** + * マテリアルのトゥーン情報を出力する。 + * @param shade シェーディング情報 + * @throws IOException 出力エラー + */ + private void putToon(ShadeInfo shade) + throws IOException{ + ind().putOpenSTag(PmdTag.TOON.tag()).sp(); + + int toonIdx = shade.getToonIndex(); + this.exp.putNumberedIdAttr(PmdAttr.TOONFILE_IDREF, + ExtraExporter.PFX_TOONFILE, toonIdx); + sp(); + + putCloseEmpty(); + + String toonFileName = shade.getToonFileName(); + if(toonFileName != null && toonFileName.length() > 0){ + sp().putLineComment(toonFileName); + } + ln(); + + return; + } + + /** + * シェーディングファイル情報を出力する。 + * @param shade シェーディング情報 + * @throws IOException 出力エラー + */ + private void putShadeFile(ShadeInfo shade) + throws IOException{ + String textureFileName = shade.getTextureFileName(); + String spheremapFileName = shade.getSpheremapFileName(); + + if(textureFileName != null && textureFileName.length() > 0){ + ind().putOpenSTag(PmdTag.TEXTURE_FILE.tag()).sp(); + putAttr(PmdAttr.WINFILE_NAME.attr(), + textureFileName).sp(); + putCloseEmpty().ln(); + } + + if(spheremapFileName != null && spheremapFileName.length() > 0){ + ind().putOpenSTag(PmdTag.SPHEREMAP_FILE.tag()).sp(); + putAttr(PmdAttr.WINFILE_NAME.attr(), + spheremapFileName).sp(); + putCloseEmpty().ln(); + } + + return; + } + + /** + * トゥーンファイルマッピング情報を出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putToonMap(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.TOON_MAP.tag()).ln(); + pushNest(); + + ToonMap map = model.getToonMap(); + for(int index = 0; index < ToonMap.MAX_CUSTOM_TOON; index++){ + ind(); + putToonDef(map, index); + ln(); + } + + popNest(); + ind().putETag(PmdTag.TOON_MAP.tag()).ln(2); + return; + } + + /** + * 個別のトゥーンファイル情報を出力する。 + * @param map トゥーンマップ + * @param index インデックス値 + * @throws IOException 出力エラー + */ + private void putToonDef(ToonMap map, int index) + throws IOException{ + putOpenSTag(PmdTag.TOON_DEF.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.TOONFILE_ID, + ExtraExporter.PFX_TOONFILE, index); + sp(); + putIntAttr(PmdAttr.INDEX.attr(), index).sp(); + String toonFile = map.getIndexedToon(index); + putAttr(PmdAttr.WINFILE_NAME.attr(), toonFile).sp(); + putCloseEmpty(); + this.exp.putUnescapedComment(toonFile); + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMorph.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMorph.java new file mode 100644 index 0000000..87dcfc6 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterMorph.java @@ -0,0 +1,122 @@ +/* + * morph xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.MorphType; +import jp.sfjp.mikutoga.pmd.model.MorphPart; +import jp.sfjp.mikutoga.pmd.model.MorphVertex; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.pmd.model.Vertex; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; + +/** + * モーフ定義のXMLエクスポーター。 + */ +class ExporterMorph extends ProxyXmlExporter { + + private static final String MORPHTYPE_COMMENT = + "Morph types:\n" + + "[1 : EYEBROW : まゆ ]\n" + + "[2 : EYE : 目 ]\n" + + "[3 : LIP : リップ ]\n" + + "[4 : EXTRA : その他 ]\n"; + + + private final ExtraExporter exp; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExporterMorph(PmdXmlExporter delegate) { + super(delegate); + this.exp = new ExtraExporter(delegate); + return; + } + + /** + * モーフ定義データを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putMorphList(PmdModel model) throws IOException{ + ind().putSimpleSTag(PmdTag.MORPH_LIST.tag()).ln(); + pushNest(); + + boolean dumped = false; + Map> morphMap = model.getMorphMap(); + for(MorphType type : MorphType.values()){ + if(type == MorphType.BASE) continue; + List partList = morphMap.get(type); + if(partList == null) continue; + for(MorphPart part : partList){ + if( ! dumped ){ + ln().putBlockComment(MORPHTYPE_COMMENT).ln(); + } + putMorphPart(part); + dumped = true; + } + } + + popNest(); + ind().putETag(PmdTag.MORPH_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のモーフ情報を出力する。 + * @param part モーフ情報 + * @throws IOException 出力エラー + */ + private void putMorphPart(MorphPart part) throws IOException{ + I18nText i18nName = part.getMorphName(); + String primary = i18nName.getPrimaryText(); + + this.exp.putLocalNameComment(i18nName); + ln(); + ind().putOpenSTag(PmdTag.MORPH.tag()).sp(); + putAttr(PmdAttr.NAME.attr(), primary).sp(); + putAttr(PmdAttr.TYPE.attr(), part.getMorphType().name()); + sp().putCloseSTag(); + ln(); + pushNest(); + + this.exp.putI18nName(i18nName); + + for(MorphVertex mvertex : part){ + MkPos3D offset = mvertex.getOffset(); + Vertex base = mvertex.getBaseVertex(); + + ind().putOpenSTag(PmdTag.MORPH_VERTEX.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.VERTEX_IDREF, + ExtraExporter.PFX_VERTEX, base); + sp(); + putFloatAttr(PmdAttr.XOFF.attr(), + (float) offset.getXpos()).sp(); + putFloatAttr(PmdAttr.YOFF.attr(), + (float) offset.getYpos()).sp(); + putFloatAttr(PmdAttr.ZOFF.attr(), + (float) offset.getZpos()).sp(); + putCloseEmpty(); + ln(); + } + + popNest(); + ind().putETag(PmdTag.MORPH.tag()).ln(2); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterShape.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterShape.java new file mode 100644 index 0000000..ce14356 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExporterShape.java @@ -0,0 +1,213 @@ +/* + * shape xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import java.util.List; +import jp.sfjp.mikutoga.math.MkPos2D; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.math.MkVec3D; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.Material; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.pmd.model.Surface; +import jp.sfjp.mikutoga.pmd.model.Vertex; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; + +/** + * 形状設定のXMLエクスポーター。 + */ +class ExporterShape extends ProxyXmlExporter { + + private final ExtraExporter exp; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExporterShape(PmdXmlExporter delegate) { + super(delegate); + this.exp = new ExtraExporter(delegate); + return; + } + + /** + * サーフェイスグループリストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putSurfaceGroupList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.SURFACE_GROUP_LIST.tag()).ln(); + + pushNest(); + int ct = 0; + boolean dumped = false; + List materialList = model.getMaterialList(); + for(Material material : materialList){ + List surfaceList = material.getSurfaceList(); + if( ! dumped ) ln(); + putSurfaceList(surfaceList, ct++); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.SURFACE_GROUP_LIST.tag()).ln(2); + + return; + } + + /** + * 個別のサーフェイスグループを出力する。 + * @param surfaceList サーフェイスのリスト + * @param index グループインデックス + * @throws IOException 出力エラー + */ + private void putSurfaceList(List surfaceList, + int index) + throws IOException{ + ind().putOpenSTag(PmdTag.SURFACE_GROUP.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.SURFACE_GROUP_ID, + ExtraExporter.PFX_SURFACEGROUP, index); + sp().putCloseSTag().ln(); + pushNest(); + + for(Surface surface : surfaceList){ + putSurface(surface); + } + + popNest(); + ind().putETag(PmdTag.SURFACE_GROUP.tag()).ln(2); + + return; + } + + /** + * 個別のサーフェイスを出力する。 + * @param surface サーフェイス + * @throws IOException 出力エラー + */ + private void putSurface(Surface surface) + throws IOException{ + ind().putOpenSTag(PmdTag.SURFACE.tag()).sp(); + + Vertex vertex1 = surface.getVertex1(); + Vertex vertex2 = surface.getVertex2(); + Vertex vertex3 = surface.getVertex3(); + + this.exp.putNumberedIdAttr(PmdAttr.VERTEX_IDREF_1, + ExtraExporter.PFX_VERTEX, vertex1); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.VERTEX_IDREF_2, + ExtraExporter.PFX_VERTEX, vertex2); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.VERTEX_IDREF_3, + ExtraExporter.PFX_VERTEX, vertex3); + sp(); + + putCloseEmpty().ln(); + return; + } + + /** + * 頂点リストを出力する。 + * @param model モデルデータ + * @throws IOException 出力エラー + */ + void putVertexList(PmdModel model) + throws IOException{ + ind().putSimpleSTag(PmdTag.VERTEX_LIST.tag()).ln(); + + pushNest(); + boolean dumped = false; + List vertexList = model.getVertexList(); + for(Vertex vertex : vertexList){ + if( ! dumped ) ln(); + putVertex(vertex); + dumped = true; + } + popNest(); + + ind().putETag(PmdTag.VERTEX_LIST.tag()).ln(2); + + return; + } + + /** + * 個別の頂点情報を出力する。 + * @param vertex 頂点 + * @throws IOException 出力エラー + */ + private void putVertex(Vertex vertex) + throws IOException{ + String bool; + if(vertex.getEdgeAppearance()) bool = "true"; + else bool = "false"; + + ind().putOpenSTag(PmdTag.VERTEX.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.VERTEX_ID, + ExtraExporter.PFX_VERTEX, vertex); + sp(); + putAttr(PmdAttr.SHOW_EDGE.attr(), bool); + sp().putCloseSTag().ln(); + pushNest(); + + putVertexBody(vertex); + + popNest(); + ind().putETag(PmdTag.VERTEX.tag()).ln(2); + + return; + } + + /** + * 頂点情報の詳細を出力する。 + * @param vertex 頂点 + * @throws IOException 出力エラー + */ + private void putVertexBody(Vertex vertex) + throws IOException{ + MkPos3D position = vertex.getPosition(); + ind(); + this.exp.putPosition(position); + ln(); + + MkVec3D normal = vertex.getNormal(); + ind().putOpenSTag(PmdTag.NORMAL.tag()).sp(); + putFloatAttr(PmdAttr.X.attr(), (float) normal.getXVal()) + .sp(); + putFloatAttr(PmdAttr.Y.attr(), (float) normal.getYVal()) + .sp(); + putFloatAttr(PmdAttr.Z.attr(), (float) normal.getZVal()) + .sp(); + putCloseEmpty().ln(); + + MkPos2D uvPos = vertex.getUVPosition(); + ind().putOpenSTag(PmdTag.UV_MAP.tag()).sp(); + putFloatAttr(PmdAttr.U.attr(), (float) uvPos.getXpos()).sp(); + putFloatAttr(PmdAttr.V.attr(), (float) uvPos.getYpos()).sp(); + putCloseEmpty().ln(); + + BoneInfo boneA = vertex.getBoneA(); + BoneInfo boneB = vertex.getBoneB(); + int weight = vertex.getWeightA(); + ind().putOpenSTag(PmdTag.SKINNING.tag()).sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF_1, + ExtraExporter.PFX_BONE, boneA); + sp(); + this.exp.putNumberedIdAttr(PmdAttr.BONE_IDREF_2, + ExtraExporter.PFX_BONE, boneB); + sp(); + putIntAttr(PmdAttr.WEIGHT_BALANCE.attr(), weight).sp(); + putCloseEmpty().ln(); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExtraExporter.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExtraExporter.java new file mode 100644 index 0000000..f276698 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/ExtraExporter.java @@ -0,0 +1,194 @@ +/* + * extra xml exporter + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.Rad3d; +import jp.sfjp.mikutoga.pmd.model.SerialNumbered; +import jp.sfjp.mikutoga.xml.ProxyXmlExporter; +import jp.sfjp.mikutoga.xml.XmlExporter; + +/** + * XML出力機構の共通部。 + */ +class ExtraExporter extends ProxyXmlExporter { + + static final String PFX_SURFACEGROUP = "sg"; + static final String PFX_TOONFILE = "tf"; + static final String PFX_VERTEX = "vtx"; + static final String PFX_BONE = "bn"; + static final String PFX_RIGID = "rd"; + static final String PFX_RIGIDGROUP = "rg"; + + private static final char CAP_BASIC_LATIN = '\u007f'; + + + /** + * コンストラクタ。 + * @param delegate 委譲先 + */ + ExtraExporter(XmlExporter delegate){ + super(delegate); + return; + } + + + /** + * 任意の文字列がBasicLatin文字のみから構成されるか判定する。 + * @param seq 文字列 + * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue + */ + static boolean hasOnlyBasicLatin(CharSequence seq){ + if(seq == null) return true; + int length = seq.length(); + for(int pos = 0; pos < length; pos++){ + char ch = seq.charAt(pos); + if(ch > CAP_BASIC_LATIN) return false; + } + return true; + } + + + /** + * 文字参照によるエスケープを補佐するためのコメントを出力する。 + * @param seq 文字列 + * @throws IOException 出力エラー + */ + void putUnescapedComment(CharSequence seq) + throws IOException{ + if( ! isBasicLatinOnlyOut() ) return; + if(hasOnlyBasicLatin(seq)) return; + sp().putLineComment(seq); + return; + } + + /** + * 多言語識別名属性のローカルな名前をコメント出力する。 + * @param name 多言語識別名 + * @throws IOException 出力エラー + */ + void putLocalNameComment(I18nText name) + throws IOException{ + String localName = name.getText(); + if(localName.isEmpty()){ + localName = "[NAMELESS]"; + } + ind().putLineComment(localName); + return; + } + + /** + * 多言語識別名属性のプライマリな名前を出力する。 + * @param attr 属性名 + * @param name 多言語識別名 + * @throws IOException 出力エラー + */ + void putPrimaryNameAttr(PmdAttr attr, I18nText name) + throws IOException{ + String attrName = attr.attr(); + String primaryName = name.getPrimaryText(); + putAttr(attrName, primaryName); + return; + } + + /** + * 多言語化された各種識別名を出力する。 + * プライマリ名は出力対象外。 + * @param text 多言語文字列 + * @throws IOException 出力エラー + */ + void putI18nName(I18nText text) throws IOException{ + for(String lang639 : text.lang639CodeList()){ + if(lang639.equals(I18nText.CODE639_PRIMARY)) continue; + String name = text.getI18nText(lang639); + ind().putOpenSTag(PmdTag.I18N_NAME.tag()).sp(); + putAttr(PmdAttr.LANG.attr(), lang639).sp(); + putAttr(PmdAttr.NAME.attr(), name).sp(); + putCloseEmpty(); + putUnescapedComment(name); + ln(); + } + return; + } + + /** + * 番号付けされたID(IDREF)属性を出力する。 + * @param attr 属性名 + * @param prefix IDプレフィクス + * @param num 番号 + * @throws IOException 出力エラー + */ + void putNumberedIdAttr(PmdAttr attr, + CharSequence prefix, + int num ) + throws IOException{ + String attrName = attr.attr(); + putRawText(attrName).putRawCh('='); + putRawCh('"'); + putRawText(prefix).putXsdInt(num); + putRawCh('"'); + return; + } + + /** + * 番号付けされたID(IDREF)属性を出力する。 + * @param attr 属性名 + * @param prefix IDプレフィクス + * @param numbered 番号付けされたオブジェクト + * @throws IOException 出力エラー + */ + void putNumberedIdAttr(PmdAttr attr, + CharSequence prefix, + SerialNumbered numbered ) + throws IOException{ + putNumberedIdAttr(attr, prefix, numbered.getSerialNumber()); + return; + } + + /** + * 位置情報を出力する。 + * @param position 位置情報 + * @throws IOException 出力エラー + */ + void putPosition(MkPos3D position) + throws IOException{ + putOpenSTag("position").sp(); + + putFloatAttr(PmdAttr.X.attr(), + (float) position.getXpos()).sp(); + putFloatAttr(PmdAttr.Y.attr(), + (float) position.getYpos()).sp(); + putFloatAttr(PmdAttr.Z.attr(), + (float) position.getZpos()).sp(); + + putCloseEmpty(); + + return; + } + + /** + * 姿勢情報(ラジアン)を出力する。 + * @param rotation 姿勢情報 + * @throws IOException 出力エラー + */ + void putRadRotation(Rad3d rotation) + throws IOException{ + putOpenSTag("radRotation").sp(); + + putFloatAttr(PmdAttr.X_RAD.attr(), rotation.getXRad()).sp(); + putFloatAttr(PmdAttr.Y_RAD.attr(), rotation.getYRad()).sp(); + putFloatAttr(PmdAttr.Z_RAD.attr(), rotation.getZRad()).sp(); + + putCloseEmpty(); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/OpenXmlMark.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/OpenXmlMark.java new file mode 100644 index 0000000..d5d9a7b --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/OpenXmlMark.java @@ -0,0 +1,23 @@ +/* + * annotation for beginning XML-element + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * XML要素開始通知用注釈。 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@interface OpenXmlMark { + /** タグ指定。 */ + PmdTag value(); +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdAttr.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdAttr.java new file mode 100644 index 0000000..1091ef0 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdAttr.java @@ -0,0 +1,123 @@ +/* + * attributes of pmd xml file + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +/** + * XML属性名一覧。 + * @see "http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-101009.xsd" + * @see "http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-130128.xsd" + * + */ +enum PmdAttr { + + VERSION ("version"), + SCHEMA_VERSION ("schemaVersion"), + + NAME ("name"), + LANG ("lang"), + + CONTENT ("content"), + + SURFACE_GROUP_IDREF ("surfaceGroupIdRef"), + R ("r"), + G ("g"), + B ("b"), + ALPHA ("alpha"), + SHININESS ("shininess"), + TOONFILE_ID ("toonFileId"), + TOONFILE_IDREF ("toonFileIdRef"), + WINFILE_NAME ("winFileName"), + INDEX ("index"), + + BONE_ID ("boneId"), + TYPE ("type"), + X ("x"), + Y ("y"), + Z ("z"), + PREV_BONE_IDREF ("prevBoneIdRef"), + NEXT_BONE_IDREF ("nextBoneIdRef"), + BONE_IDREF ("boneIdRef"), + RATIO ("ratio"), + + IK_BONE_IDREF ("ikBoneIdRef"), + RECURSIVE_DEPTH ("recursiveDepth"), + WEIGHT ("weight"), + + VERTEX_IDREF ("vtxIdRef"), + XOFF ("xOff"), + YOFF ("yOff"), + ZOFF ("zOff"), + + RIGID_ID ("rigidId"), + RIGID_IDREF ("rigidIdRef"), + BEHAVIOR ("behavior"), + RADIUS ("radius"), + WIDTH ("width"), + HEIGHT ("height"), + DEPTH ("depth"), + X_RAD ("xRad"), + Y_RAD ("yRad"), + Z_RAD ("zRad"), + + MASS ("mass"), + DAMPING_POSITION ("dampingPosition"), + DAMPING_ROTATION ("dampingRotation"), + RESTITUTION ("restitution"), + FRICTION ("friction"), + + RIGID_GROUP_ID ("rigidGroupId"), + RIGID_GROUP_IDREF ("rigidGroupIdRef"), + + RIGID_IDREF_1 ("rigidIdRef1"), + RIGID_IDREF_2 ("rigidIdRef2"), + X_FROM ("xFrom"), + X_TO ("xTo"), + Y_FROM ("yFrom"), + Y_TO ("yTo"), + Z_FROM ("zFrom"), + Z_TO ("zTo"), + X_DEG ("xDeg"), + Y_DEG ("yDeg"), + Z_DEG ("zDeg"), + + SURFACE_GROUP_ID ("surfaceGroupId"), + VERTEX_IDREF_1 ("vtxIdRef1"), + VERTEX_IDREF_2 ("vtxIdRef2"), + VERTEX_IDREF_3 ("vtxIdRef3"), + + VERTEX_ID ("vtxId"), + SHOW_EDGE ("showEdge"), + U ("u"), + V ("v"), + BONE_IDREF_1 ("boneIdRef1"), + BONE_IDREF_2 ("boneIdRef2"), + WEIGHT_BALANCE ("weightBalance"), + + ; + + private final String attrName; + + + /** + * コンストラクタ。 + * @param attrName 属性名 + */ + private PmdAttr(String attrName){ + this.attrName = attrName.intern(); + return; + } + + /** + * 属性名を返す。 + * @return 属性名 + */ + String attr(){ + return this.attrName; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdTag.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdTag.java new file mode 100644 index 0000000..d7a977f --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdTag.java @@ -0,0 +1,138 @@ +/* + * tags of pmd xml file + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.HashMap; +import java.util.Map; + +/** + * XML要素名一覧。 + * @see "http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-101009.xsd" + * @see "http://mikutoga.sourceforge.jp/xml/xsd/pmdxml-130128.xsd" + */ +enum PmdTag { + + PMD_MODEL ("pmdModel"), + + BR ("br"), + I18N_NAME ("i18nName"), + DESCRIPTION ("description"), + LICENSE ("license"), + CREDITS ("credits"), + META ("meta"), + + MATERIAL_LIST ("materialList"), + MATERIAL ("material"), + DIFFUSE ("diffuse"), + SPECULAR ("specular"), + AMBIENT ("ambient"), + TOON ("toon"), + TEXTURE_FILE ("textureFile"), + SPHEREMAP_FILE ("spheremapFile"), + + TOON_MAP ("toonMap"), + TOON_DEF ("toonDef"), + + BONE_LIST ("boneList"), + BONE ("bone"), + POSITION ("position"), + IK_BONE ("ikBone"), + SOURCE_BONE ("sourceBone"), + ROTATION_RATIO ("rotationRatio"), + BONE_CHAIN ("boneChain"), + + BONE_GROUP_LIST ("boneGroupList"), + BONE_GROUP ("boneGroup"), + BONE_GROUP_MEMBER ("boneGroupMember"), + + IK_CHAIN_LIST ("ikChainList"), + IK_CHAIN ("ikChain"), + CHAIN_ORDER ("chainOrder"), + + MORPH_LIST ("morphList"), + MORPH ("morph"), + MORPH_VERTEX ("morphVertex"), + + RIGID_LIST ("rigidList"), + RIGID ("rigid"), + LINKED_BONE ("linkedBone"), + RIGID_SHAPE_SPHERE ("rigidShapeSphere"), + RIGID_SHAPE_BOX ("rigidShapeBox"), + RIGID_SHAPE_CAPSULE ("rigidShapeCapsule"), + RAD_ROTATION ("radRotation"), + DYNAMICS ("dynamics"), + THROUGH_RIGID_GROUP ("throughRigidGroup"), + + RIGID_GROUP_LIST ("rigidGroupList"), + RIGID_GROUP ("rigidGroup"), + RIGID_GROUP_MEMBER ("rigidGroupMember"), + + JOINT_LIST ("jointList"), + JOINT ("joint"), + JOINTED_RIGID_PAIR ("jointedRigidPair"), + LIMIT_POSITION ("limitPosition"), + LIMIT_ROTATION ("limitRotation"), + ELASTIC_POSITION ("elasticPosition"), + ELASTIC_ROTATION ("elasticRotation"), + + SURFACE_GROUP_LIST ("surfaceGroupList"), + SURFACE_GROUP ("surfaceGroup"), + SURFACE ("surface"), + + VERTEX_LIST ("vertexList"), + VERTEX ("vertex"), + NORMAL ("normal"), + UV_MAP ("uvMap"), + SKINNING ("skinning"), + + ; + + private static final Map NAME_MAP = + new HashMap(); + + static{ + for(PmdTag tag : values()){ + NAME_MAP.put(tag.tag(), tag); + } + } + + + private final String tagName; + + + /** + * コンストラクタ。 + * @param tagName 要素名 + */ + private PmdTag(String tagName){ + this.tagName = tagName.intern(); + return; + } + + + /** + * XML要素名から列挙子を得る。 + * @param name 要素名 + * @return 列挙子。合致する物がなければnull。 + */ + static PmdTag parse(String name){ + PmdTag result; + result = NAME_MAP.get(name); + return result; + } + + + /** + * XML要素名を返す。 + * @return 要素名 + */ + String tag(){ + return this.tagName; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdXmlExporter.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdXmlExporter.java new file mode 100644 index 0000000..01f5a8a --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/PmdXmlExporter.java @@ -0,0 +1,366 @@ +/* + * pmd-xml exporter + * + * License : The MIT License + * Copyright(c) 2010 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.xml.BasicXmlExporter; +import jp.sfjp.mikutoga.xml.XmlResourceResolver; + +/** + * PMDモーションデータをXMLへエクスポートする。 + */ +public class PmdXmlExporter extends BasicXmlExporter{ + + private static final String XML_VER = "1.0"; + private static final String XML_ENC = "UTF-8"; + private static final String XML_DECL = + ""; + + private static final String XSINS = "xsi"; + + private static final String TOP_COMMENT = + "\u0020\u0020" + "MikuMikuDance\n" + + "\u0020\u0020\u0020\u0020" + "model-data(*.pmd) on XML"; + + /** 改行文字列 CR。 */ + private static final String CR = "\r"; // 0x0d + /** 改行文字列 LF。 */ + private static final String LF = "\n"; // 0x0a + /** 改行文字列 CRLF。 */ + private static final String CRLF = CR + LF; // 0x0d, 0x0a + + + private XmlModelFileType xmlType = XmlModelFileType.XML_130128; + + private String generator = null; + + private final ExporterMaterial materialExporter; + private final ExporterBone boneExporter; + private final ExporterMorph morphExporter; + private final ExporterDynamics dynamicsExporter; + private final ExporterShape shapeExporter; + + private final ExtraExporter exp; + + + /** + * コンストラクタ。 + */ + public PmdXmlExporter(){ + super(); + + this.materialExporter = new ExporterMaterial(this); + this.boneExporter = new ExporterBone(this); + this.morphExporter = new ExporterMorph(this); + this.dynamicsExporter = new ExporterDynamics(this); + this.shapeExporter = new ExporterShape(this); + + this.exp = new ExtraExporter(this); + + this.boneExporter.setXmlFileType(this.xmlType); + + return; + } + + + /** + * 出力XMLファイル種別を返す。 + * @return ファイル種別 + */ + public XmlModelFileType getXmlFileType(){ + return this.xmlType; + } + + /** + * 出力XMLファイル種別を設定する。 + * @param type ファイル種別 + */ + public void setXmlFileType(XmlModelFileType type){ + switch(type){ + case XML_101009: + case XML_130128: + this.xmlType = type; + break; + case XML_AUTO: + this.xmlType = XmlModelFileType.XML_130128; + break; + default: + throw new IllegalArgumentException(); + } + + assert this.xmlType == XmlModelFileType.XML_101009 + || this.xmlType == XmlModelFileType.XML_130128; + + this.boneExporter.setXmlFileType(this.xmlType); + + return; + } + + /** + * Generatorメタ情報を設定する。 + * @param generatorArg Generatorメタ情報。表示したくないときはnull + */ + public void setGenerator(String generatorArg){ + this.generator = generatorArg; + return; + } + + /** + * Generatorメタ情報を返す。 + * @return Generatorメタ情報。表示したくないときはnull + */ + public String getGenerator(){ + return this.generator; + } + + /** + * PMDモデルデータをXML形式で出力する。 + * @param model PMDモデルデータ + * @param xmlOut XML出力先 + * @throws IOException 出力エラー + */ + public void putPmdXml(PmdModel model, Appendable xmlOut) + throws IOException{ + setAppendable(xmlOut); + + try{ + putPmdXmlImpl(model); + }finally{ + flush(); + } + + return; + } + + /** + * PMDモデルデータをXML形式で出力する。 + * @param model PMDモデルデータ + * @throws IOException 出力エラー + */ + private void putPmdXmlImpl(PmdModel model) throws IOException{ + putPmdRootOpen(model); + + putModelInfo(model); + putMetaInfo(); + + this.materialExporter.putMaterialList(model); + this.materialExporter.putToonMap(model); + + this.boneExporter.putBoneList(model); + this.boneExporter.putBoneGroupList(model); + this.boneExporter.putIKChainList(model); + + this.morphExporter.putMorphList(model); + + this.dynamicsExporter.putRigidList(model); + this.dynamicsExporter.putRigidGroupList(model); + this.dynamicsExporter.putJointList(model); + + this.shapeExporter.putSurfaceGroupList(model); + this.shapeExporter.putVertexList(model); + + ind().putETag(PmdTag.PMD_MODEL.tag()).ln(2); + ind().putLineComment("EOF").ln(); + + return; + } + + /** + * ルートタグ開始を出力する。 + * @param model モデル情報 + * @throws IOException 出力エラー + */ + private void putPmdRootOpen(PmdModel model) + throws IOException{ + ind().putRawText(XML_DECL).ln(2); + ind().putBlockComment(TOP_COMMENT).ln(2); + + I18nText modelName = model.getModelName(); + ind(); + this.exp.putLocalNameComment(modelName); + ln(); + + ind().putOpenSTag(PmdTag.PMD_MODEL.tag()).ln(); + pushNest(); + + putPmdRootAttr(model); + + popNest(); + putCloseSTag().ln(2); + + return; + } + + /** + * ルートタグ属性を出力する。 + * @param model モデル情報 + * @throws IOException 出力エラー + */ + private void putPmdRootAttr(PmdModel model) + throws IOException{ + String namespace; + String schemaUrl; + String schemaVer; + + if(this.xmlType == XmlModelFileType.XML_101009){ + namespace = Schema101009.NS_PMDXML; + schemaUrl = Schema101009.SCHEMA_PMDXML; + schemaVer = Schema101009.VER_PMDXML; + }else if(this.xmlType == XmlModelFileType.XML_130128){ + namespace = Schema130128.NS_PMDXML; + schemaUrl = Schema130128.SCHEMA_PMDXML; + schemaVer = Schema130128.VER_PMDXML; + }else{ + assert false; + throw new AssertionError(); + } + + ind().putAttr("xmlns", namespace).ln(); + ind().putAttr("xmlns:" + XSINS, XmlResourceResolver.NS_XSD).ln(); + + ind().putRawText(XSINS).putRawText(":schemaLocation=") + .putRawCh('"'); + putRawText(namespace).ln(); + ind().sp(2).putRawText(schemaUrl) + .putRawCh('"').ln(); + + ind().putAttr(PmdAttr.SCHEMA_VERSION.attr(), schemaVer); + ln(2); + + I18nText modelName = model.getModelName(); + ind(); + this.exp.putPrimaryNameAttr(PmdAttr.NAME, modelName); + ln(); + + return; + } + + /** + * モデル基本情報を出力する。 + * @param model モデル情報 + * @return this本体 + * @throws IOException 出力エラー + */ + private PmdXmlExporter putModelInfo(PmdModel model) + throws IOException{ + I18nText modelName = model.getModelName(); + this.exp.putI18nName(modelName); + ln(); + + I18nText description = model.getDescription(); + for(String lang639 : description.lang639CodeList()){ + String descText = description.getI18nText(lang639); + putDescription(lang639, descText); + ln(); + } + + return this; + } + + /** + * モデル詳細テキストを出力する。 + * @param lang639 言語コード + * @param content 詳細内容 + * @return this本体 + * @throws IOException 出力エラー + */ + private PmdXmlExporter putDescription(CharSequence lang639, + CharSequence content) + throws IOException{ + String text = content.toString(); + text = text.replace(CRLF, LF); + text = text.replace(CR, LF); + + ind().putOpenSTag(PmdTag.DESCRIPTION.tag()); + if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){ + sp().putAttr(PmdAttr.LANG.attr(), lang639).sp(); + } + putCloseSTag().ln(); + + putBRedContent(text); + + ind().putETag(PmdTag.DESCRIPTION.tag()).ln(); + + if( ! ExtraExporter.hasOnlyBasicLatin(text) + && isBasicLatinOnlyOut() ){ + putBlockComment(text); + } + + return this; + } + + /** + * break要素を含む要素内容を出力する。 + * 必要に応じてXML定義済み実体文字が割り振られた文字、 + * コントロールコード、および非BasicLatin文字がエスケープされる。 + * \nはbrタグに変換される。 + * @param content 内容 + * @return this本体 + * @throws IOException 出力エラー + */ + private PmdXmlExporter putBRedContent(CharSequence content) + throws IOException{ + int length = content.length(); + + int startPos = 0; + + for(int idx = 0; idx < length; idx++){ + char ch = content.charAt(idx); + if(ch == '\n'){ + CharSequence seq = content.subSequence(startPos, idx); + putContent(seq).putRawText("
").ln(); + startPos = idx + 1; + } + } + + if(startPos < length){ + CharSequence seq = content.subSequence(startPos, length); + putContent(seq).ln(); + } + + return this; + } + + /** + * 各種メタ情報を出力する。 + * @return this本体 + * @throws IOException 出力エラー + */ + private PmdXmlExporter putMetaInfo() throws IOException{ + ind().putSimpleSTag(PmdTag.LICENSE.tag()).ln(); + ind().putETag(PmdTag.LICENSE.tag()).ln(2); + + ind().putSimpleSTag(PmdTag.CREDITS.tag()).ln(); + ind().putETag(PmdTag.CREDITS.tag()).ln(2); + + String genName = getGenerator(); + if(genName != null){ + ind().putOpenSTag(PmdTag.META.tag()).sp(); + putAttr(PmdAttr.NAME.attr(), "generator").sp(); + putAttr(PmdAttr.CONTENT.attr(), genName).sp(); + putCloseEmpty().ln(); + } + + ind().putOpenSTag(PmdTag.META.tag()).sp(); + putAttr(PmdAttr.NAME.attr(), "siteURL").sp(); + putAttr(PmdAttr.CONTENT.attr(), "").sp(); + putCloseEmpty().ln(); + + ind().putOpenSTag(PmdTag.META.tag()).sp(); + putAttr(PmdAttr.NAME.attr(), "imageURL").sp(); + putAttr(PmdAttr.CONTENT.attr(), "").sp(); + putCloseEmpty().ln(2); + + return this; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/RefHelper.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/RefHelper.java new file mode 100644 index 0000000..86d7e46 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/RefHelper.java @@ -0,0 +1,478 @@ +/* + * SAX ID-reference helper + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.Material; +import jp.sfjp.mikutoga.pmd.model.MorphVertex; +import jp.sfjp.mikutoga.pmd.model.RigidGroup; +import jp.sfjp.mikutoga.pmd.model.RigidInfo; +import jp.sfjp.mikutoga.pmd.model.ShadeInfo; +import jp.sfjp.mikutoga.pmd.model.Surface; +import jp.sfjp.mikutoga.pmd.model.Vertex; + +/** + * 各種ID参照解決用の一時的なヘルパ。 + */ +class RefHelper { + + // マテリアル関連 + private final List> materialSfcGroupIdRefList = + new LinkedList>(); + private final List> materialToonIdRefList = + new LinkedList>(); + private final Map toonIdxMap = + new HashMap(); + + // ボーン関連 + private final Map boneIdMap = + new HashMap(); + private final List> boneChainIdRefList = + new LinkedList>(); + private final List> boneSourceIdRefList = + new LinkedList>(); + + // モーフ関連 + private final List> morphVertexIdRefList = + new LinkedList>(); + + // 剛体関連 + private final Map rigidIdMap = + new HashMap(); + private final Map rigidGroupIdMap = + new HashMap(); + private final List> thghRigidGroupIdRefList = + new LinkedList>(); + + // 面関連 + private final Map> surfaceGroupIdMap = + new HashMap>(); + private final List> surfaceVertexIdRef = + new LinkedList>(); + + // 頂点関連 + private final Map vertexIdMap = + new HashMap(); + + + /** + * コンストラクタ。 + */ + RefHelper(){ + super(); + return; + } + + + /** + * マテリアルからのサーフェイスグループID参照を登録する。 + * @param material マテリアル + * @param idRef サーフェイスグループID参照 + */ + void addSurfaceGroupIdRef(Material material, String idRef){ + IdRefHolder holder = + new IdRefHolder(material, idRef); + this.materialSfcGroupIdRefList.add(holder); + + return; + } + + /** + * サーフェイスグループの構成サーフェイスを登録する。 + * @param surfaceGroupId サーフェイスグループID + * @param surface サーフェイス + */ + void addSurfaceGroup(String surfaceGroupId, Surface surface){ + List surfaceGroup = + this.surfaceGroupIdMap.get(surfaceGroupId); + if(surfaceGroup == null){ + surfaceGroup = new LinkedList(); + this.surfaceGroupIdMap.put(surfaceGroupId, surfaceGroup); + } + + surfaceGroup.add(surface); + + return; + } + + /** + * マテリアルからのサーフェイスグループID参照を解決する。 + */ + void resolveMaterialSurfaceGroupId(){ + for(IdRefHolder holder : this.materialSfcGroupIdRefList){ + Material material = holder.getBody(); + String surfaceGroupIdRef = holder.getIdRef(); + + List surfaceGroup = + this.surfaceGroupIdMap.get(surfaceGroupIdRef); + + List surfaceList = material.getSurfaceList(); + surfaceList.addAll(surfaceGroup); + } + + return; + } + + /** + * マテリアルからの共有トゥーンファイルID参照を追加登録する。 + * @param material マテリアル + * @param idRef トゥーンファイルID参照 + */ + void addToonFileIdRef(Material material, String idRef){ + IdRefHolder holder = + new IdRefHolder(material, idRef); + this.materialToonIdRefList.add(holder); + return; + } + + /** + * 共有トゥーンファイルのインデックスを登録する。 + * @param toonFileId ToonファイルID + * @param idx 共有Toonインデックス + */ + void addToonIdx(String toonFileId, int idx){ + this.toonIdxMap.put(toonFileId, idx); + return; + } + + /** + * マテリアルからの共有トゥーンインデックスの参照問題を解決する。 + */ + void resolveToonIdx(){ + for(IdRefHolder holder : this.materialToonIdRefList){ + Material material = holder.getBody(); + String toonFileIdRef = holder.getIdRef(); + int toonIdx = this.toonIdxMap.get(toonFileIdRef); + + ShadeInfo shadeInfo = material.getShadeInfo(); + shadeInfo.setToonIndex(toonIdx); + } + + return; + } + + /** + * ボーンIDを登録する。 + * @param boneId ボーンID + * @param boneInfo ボーン情報 + */ + void addBoneId(String boneId, BoneInfo boneInfo){ + this.boneIdMap.put(boneId, boneInfo); + return; + } + + /** + * ボーンIDを問い合わせる。 + * @param boneId ボーンID + * @return ボーン情報 + */ + BoneInfo findBoneId(String boneId){ + BoneInfo result = this.boneIdMap.get(boneId); + return result; + } + + /** + * ボーン間チェーン参照情報を登録する。 + * @param bone ボーン情報 + * @param prevBoneIdRef 前ボーンID参照 + * @param nextBoneIdRef 次ボーンID参照 + */ + void addBoneChain(BoneInfo bone, + String prevBoneIdRef, String nextBoneIdRef ){ + IdRefHolder holder = + new IdRefHolder(bone, prevBoneIdRef, nextBoneIdRef); + this.boneChainIdRefList.add(holder); + return; + } + + /** + * ボーン間チェーン参照情報を解決する。 + */ + void resolveBoneChainIdRef(){ + for(IdRefHolder holder : this.boneChainIdRefList){ + BoneInfo bone = holder.getBody(); + String prevBoneIdRef = holder.getIdRef(); + String nextBoneIdRef = holder.getIdRef2(); + + if(prevBoneIdRef != null){ + BoneInfo prevBone = this.boneIdMap.get(prevBoneIdRef); + bone.setPrevBone(prevBone); + } + + if(nextBoneIdRef != null){ + BoneInfo nextBone = this.boneIdMap.get(nextBoneIdRef); + bone.setNextBone(nextBone); + } + } + + return; + } + + /** + * ボーン情報からのソースボーンID参照を登録する。 + * @param bone ボーン情報 + * @param srcBoneIdRef ソースボーンID参照 + */ + void addSrcBoneIdRef(BoneInfo bone, String srcBoneIdRef){ + IdRefHolder holder = + new IdRefHolder(bone, srcBoneIdRef); + this.boneSourceIdRefList.add(holder); + return; + } + + /** + * ボーン情報からのソースボーンID参照を解決する。 + */ + void resolveSrcBoneIdRef(){ + for(IdRefHolder holder : this.boneSourceIdRefList){ + BoneInfo bone = holder.getBody(); + String srcBoneIdRef = holder.getIdRef(); + if(srcBoneIdRef == null) continue; + + BoneInfo srcBone = this.boneIdMap.get(srcBoneIdRef); + bone.setSrcBone(srcBone); + } + + return; + } + + /** + * モーフ頂点からの頂点ID参照を登録する。 + * @param morphVertex モーフ頂点 + * @param vertexIdRef 頂点ID参照 + */ + void addMorphVertexIdRef(MorphVertex morphVertex, String vertexIdRef){ + IdRefHolder holder = + new IdRefHolder(morphVertex, vertexIdRef); + this.morphVertexIdRefList.add(holder); + return; + } + + /** + * 剛体IDを登録する。 + * @param rigidId 剛体ID + * @param rigid 剛体情報 + */ + void addRigidId(String rigidId, RigidInfo rigid){ + this.rigidIdMap.put(rigidId, rigid); + return; + } + + /** + * 剛体IDを問い合わせる。 + * @param rigidId 剛体ID + * @return 剛体情報 + */ + RigidInfo findRigidId(String rigidId){ + RigidInfo result = this.rigidIdMap.get(rigidId); + return result; + } + + /** + * 剛体からの通過剛体グループID参照を登録する。 + * @param rigid 剛体情報 + * @param rigidGroupIdRef 剛体グループID参照 + */ + void addThroughRigidGroupIdRef(RigidInfo rigid, String rigidGroupIdRef){ + IdRefHolder holder = + new IdRefHolder(rigid, rigidGroupIdRef); + this.thghRigidGroupIdRefList.add(holder); + return; + } + + /** + * 剛体グループIDを登録する。 + * @param rigidGroupId 剛体グループID + * @param rigidGroup 剛体グループ + */ + void addRigidGroupId(String rigidGroupId, RigidGroup rigidGroup){ + this.rigidGroupIdMap.put(rigidGroupId, rigidGroup); + return; + } + + /** + * 剛体グループID参照を解決する。 + */ + void resolveThroughRigidGroupIdRef(){ + for(IdRefHolder holder : this.thghRigidGroupIdRefList){ + RigidInfo rigid = holder.getBody(); + String rigidGroupIdRef = holder.getIdRef(); + RigidGroup group = this.rigidGroupIdMap.get(rigidGroupIdRef); + + Collection throughGroups = + rigid.getThroughGroupColl(); + throughGroups.add(group); + } + + return; + } + + /** + * 三角ポリゴンサーフェイス面からの頂点ID参照を登録する。 + * @param surface surface面 + * @param vtxIdRef1 頂点ID参照その1 + * @param vtxIdRef2 頂点ID参照その2 + * @param vtxIdRef3 頂点ID参照その3 + */ + void addSurfaceVertex(Surface surface, + String vtxIdRef1, + String vtxIdRef2, + String vtxIdRef3 ){ + IdRefHolder holder = + new IdRefHolder(surface, + vtxIdRef1, + vtxIdRef2, + vtxIdRef3 ); + + this.surfaceVertexIdRef.add(holder); + + return; + } + + /** + * 頂点IDを登録する。 + * @param vertexId 頂点ID + * @param vertex 頂点 + */ + void addVertexId(String vertexId, Vertex vertex){ + this.vertexIdMap.put(vertexId, vertex); + return; + } + + /** + * モーフ頂点からの頂点ID参照を解決する。 + */ + void resolveMorphVertexIdRef(){ + for(IdRefHolder holder : this.morphVertexIdRefList){ + MorphVertex morphVertex = holder.getBody(); + String vertexIdRef = holder.getIdRef(); + Vertex vertex = this.vertexIdMap.get(vertexIdRef); + + morphVertex.setBaseVertex(vertex); + } + + return; + } + + /** + * サーフェイスからの頂点ID参照を解決する。 + */ + void resolveSurfaceVertexIdRef(){ + for(IdRefHolder holder : this.surfaceVertexIdRef){ + Surface surface = holder.getBody(); + String vertexIdRef1 = holder.getIdRef(); + String vertexIdRef2 = holder.getIdRef2(); + String vertexIdRef3 = holder.getIdRef3(); + + Vertex vtx1 = this.vertexIdMap.get(vertexIdRef1); + Vertex vtx2 = this.vertexIdMap.get(vertexIdRef2); + Vertex vtx3 = this.vertexIdMap.get(vertexIdRef3); + + surface.setTriangle(vtx1, vtx2, vtx3); + } + + return; + } + + /** + * ID参照解決用一時ホルダ。 + * 必要に応じて参照IDを3つまで持てる。 + * @param ID参照元インスタンス型 + */ + private static final class IdRefHolder { + + private final E body; + + private final String idRef; + private final String idRef2; + private final String idRef3; + + /** + * コンストラクタ。 + * @param body ID参照元インスタンス + * @param idRef 参照ID + */ + IdRefHolder(E body, String idRef){ + this(body, idRef, null, null); + return; + } + + /** + * コンストラクタ。 + * @param body ID参照元インスタンス + * @param idRef 参照ID + * @param idRef2 参照IDその2 + */ + IdRefHolder(E body, String idRef, String idRef2){ + this(body, idRef, idRef2, null); + return; + } + + /** + * コンストラクタ。 + * @param body ID参照元インスタンス + * @param idRef 参照ID + * @param idRef2 参照IDその2 + * @param idRef3 参照IDその3 + */ + IdRefHolder(E body, + String idRef, + String idRef2, + String idRef3 ){ + super(); + + this.body = body; + + this.idRef = idRef; + this.idRef2 = idRef2; + this.idRef3 = idRef3; + + return; + } + + + /** + * ID参照元インスタンスを返す。 + * @return ID参照元インスタンス + */ + private E getBody(){ + return this.body; + } + + /** + * 参照IDを返す。 + * @return 参照ID + */ + private String getIdRef(){ + return this.idRef; + } + + /** + * 参照IDその2を返す。 + * @return 参照ID + */ + private String getIdRef2(){ + return this.idRef2; + } + + /** + * 参照IDその3を返す。 + * @return 参照ID + */ + private String getIdRef3(){ + return this.idRef3; + } + + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxBoneListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxBoneListener.java new file mode 100644 index 0000000..8e3b7e0 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxBoneListener.java @@ -0,0 +1,307 @@ +/* + * bone listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.List; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.BoneType; +import jp.sfjp.mikutoga.pmd.model.BoneGroup; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.IKChain; +import jp.sfjp.mikutoga.pmd.model.ListUtil; + +/* + + boneList + + bone + + i18nName + + position + + rotationRatio + + ikBone + + sourceBone + + boneChain + + boneGroupList + + boneGroup + + i18nName + + boneGroupMember + + ikChainList + + ikChain + + chainOrder +*/ + +/** + * ボーン関連のXML要素出現イベントを受信する。 + */ +class SaxBoneListener extends SaxListener{ + + private final RefHelper helper; + + private BoneInfo currentBone = null; + + private BoneGroup currentBoneGroup = null; + + private IKChain currentIkChain = null; + + + /** + * コンストラクタ。 + * @param helper 参照ヘルパ + */ + SaxBoneListener(RefHelper helper) { + super(); + this.helper = helper; + return; + } + + + /** + * boneInfoタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.BONE) + void openBoneInfo(){ + this.currentBone = new BoneInfo(); + + String nameAttr = getStringAttr(PmdAttr.NAME); + I18nText boneName = this.currentBone.getBoneName(); + boneName.setPrimaryText(nameAttr); + + String boneId = getStringAttr(PmdAttr.BONE_ID); + this.helper.addBoneId(boneId, this.currentBone); + + String typeAttr = getStringAttr(PmdAttr.TYPE); + BoneType boneType = BoneType.valueOf(typeAttr); + this.currentBone.setBoneType(boneType); + + return; + } + + /** + * boneInfoタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.BONE) + void closeBoneInfo(){ + List boneList = getPmdModel().getBoneList(); + boneList.add(this.currentBone); + + this.currentBone = null; + + return; + } + + /** + * i18nTextタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.I18N_NAME) + void openI18nText(){ + I18nText i18nName; + if(this.currentBone != null){ + i18nName = this.currentBone.getBoneName(); + }else if(this.currentBoneGroup != null){ + i18nName = this.currentBoneGroup.getGroupName(); + }else{ + return; + } + + String lang = getStringAttr(PmdAttr.LANG); + String name = getStringAttr(PmdAttr.NAME); + + i18nName.setI18nText(lang, name); + + return; + } + + /** + * boneListタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.BONE_LIST) + void closeBoneList(){ + this.helper.resolveSrcBoneIdRef(); + this.helper.resolveBoneChainIdRef(); + + List boneList = getPmdModel().getBoneList(); + ListUtil.assignIndexedSerial(boneList); + + return; + } + + /** + * positionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.POSITION) + void openPosition(){ + float x = getFloatAttr(PmdAttr.X); + float y = getFloatAttr(PmdAttr.Y); + float z = getFloatAttr(PmdAttr.Z); + + MkPos3D pos = this.currentBone.getPosition(); + pos.setPosition(x, y, z); + + return; + } + + /** + * rotationRatioタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.ROTATION_RATIO) + void openRotationRatio(){ + int ratio = getIntAttr(PmdAttr.RATIO); + this.currentBone.setRotationRatio(ratio); + return; + } + + /** + * ikBoneタグ開始の通知を受け取る。 + * ※ 101009版スキーマでしか出現しない。 + */ + @OpenXmlMark(PmdTag.IK_BONE) // 101009 only + void openIkBone(){ + openSrcBone(); + return; + } + + /** + * sourceBoneタグ開始の通知を受け取る。 + * ※ 130128版スキーマでしか出現しない。 + */ + @OpenXmlMark(PmdTag.SOURCE_BONE) // 130128 only + void openSrcBone(){ + String boneIdRef = getStringAttr(PmdAttr.BONE_IDREF); + this.helper.addSrcBoneIdRef(this.currentBone, boneIdRef); + return; + } + + /** + * boneChainタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.BONE_CHAIN) + void openBoneChain(){ + String prevBoneIdRef = getStringAttr(PmdAttr.PREV_BONE_IDREF); + String nextBoneIdRef = getStringAttr(PmdAttr.NEXT_BONE_IDREF); + + this.helper.addBoneChain(this.currentBone, + prevBoneIdRef, nextBoneIdRef ); + + return; + } + + /** + * boneGroupListタグ開始の通知を受け取る。 + * 暗黙のデフォルトボーングループが無条件に格納される。 + */ + @OpenXmlMark(PmdTag.BONE_GROUP_LIST) + void openBoneGroupList(){ + BoneGroup defaultBoneGroup = new BoneGroup(); + defaultBoneGroup.setSerialNumber(0); + + List boneGroupList = + this.getPmdModel().getBoneGroupList(); + boneGroupList.add(defaultBoneGroup); + + return; + } + + /** + * boneGroupListタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.BONE_GROUP_LIST) + void closeBoneGroupList(){ + List boneGroupList = getPmdModel().getBoneGroupList(); + ListUtil.assignIndexedSerial(boneGroupList); + return; + } + + /** + * boneGroupタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.BONE_GROUP) + void openBoneGroup(){ + this.currentBoneGroup = new BoneGroup(); + + String nameAttr = getStringAttr(PmdAttr.NAME); + I18nText groupName = this.currentBoneGroup.getGroupName(); + groupName.setPrimaryText(nameAttr); + + return; + } + + /** + * boneGroupタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.BONE_GROUP) + void closeBoneGroup(){ + List boneGroupList = getPmdModel().getBoneGroupList(); + boneGroupList.add(this.currentBoneGroup); + + this.currentBoneGroup = null; + + return; + } + + /** + * boneGroupMemberタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.BONE_GROUP_MEMBER) + void openBoneGroupMember(){ + String boneIdRef = getStringAttr(PmdAttr.BONE_IDREF); + + BoneInfo bone = this.helper.findBoneId(boneIdRef); + + List boneList = this.currentBoneGroup.getBoneList(); + boneList.add(bone); + + return; + } + + /** + * ikChainタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.IK_CHAIN) + void openIkChain(){ + this.currentIkChain = new IKChain(); + + String ikBoneIdRef = getStringAttr(PmdAttr.IK_BONE_IDREF); + BoneInfo bone = this.helper.findBoneId(ikBoneIdRef); + this.currentIkChain.setIkBone(bone); + + int depth = getIntAttr(PmdAttr.RECURSIVE_DEPTH); + this.currentIkChain.setIKDepth(depth); + + float weight = getFloatAttr(PmdAttr.WEIGHT); + this.currentIkChain.setIKWeight(weight); + + return; + } + + /** + * ikChainタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.IK_CHAIN) + void closeIkChain(){ + List ikChainList = getPmdModel().getIKChainList(); + ikChainList.add(this.currentIkChain); + + this.currentIkChain = null; + + return; + } + + /** + * chainOrderタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.CHAIN_ORDER) + void openChainOrder(){ + String boneIdRef = getStringAttr(PmdAttr.BONE_IDREF); + BoneInfo bone = this.helper.findBoneId(boneIdRef); + + List chainList = this.currentIkChain.getChainedBoneList(); + chainList.add(bone); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxDynamicsListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxDynamicsListener.java new file mode 100644 index 0000000..e8b839e --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxDynamicsListener.java @@ -0,0 +1,479 @@ +/* + * dynamics listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.List; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.Deg3d; +import jp.sfjp.mikutoga.pmd.Rad3d; +import jp.sfjp.mikutoga.pmd.RigidBehaviorType; +import jp.sfjp.mikutoga.pmd.RigidShapeType; +import jp.sfjp.mikutoga.pmd.TripletRange; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.DynamicsInfo; +import jp.sfjp.mikutoga.pmd.model.JointInfo; +import jp.sfjp.mikutoga.pmd.model.ListUtil; +import jp.sfjp.mikutoga.pmd.model.RigidGroup; +import jp.sfjp.mikutoga.pmd.model.RigidInfo; +import jp.sfjp.mikutoga.pmd.model.RigidShape; + +/* + + rigidList + + rigid + + i18nName + + linkedBone + + rigidShapeSphere + + rigidShapeBox + + rigidShapeCapsule + + position + + radRotation + + dynamics + + throughRigidGroup + + rigidGroupList + + rigidGroup + + rigidGroupMember + + jointList + + joint + + i18nName + + jointedRigidPair + + position + + limitPosition + + radRotation + + limitRotation + + elasticPosition + + elasticRotation +*/ + +/** + * 剛体力学関連のXML要素出現イベントを受信する。 + */ +class SaxDynamicsListener extends SaxListener{ + + private final RefHelper helper; + + private RigidInfo currentRigid = null; + private RigidGroup currentRigidGroup = null; + private JointInfo currentJoint = null; + + + /** + * コンストラクタ。 + * @param helper 参照ヘルパ + */ + SaxDynamicsListener(RefHelper helper) { + super(); + this.helper = helper; + return; + } + + + /** + * rigidListタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.RIGID_LIST) + void closeRigidList(){ + List rigidList = getPmdModel().getRigidList(); + ListUtil.assignIndexedSerial(rigidList); + return; + } + + /** + * rigidタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID) + void openRigid(){ + this.currentRigid = new RigidInfo(); + + String name = getStringAttr(PmdAttr.NAME); + I18nText rigidName = this.currentRigid.getRigidName(); + rigidName.setPrimaryText(name); + + String rigidId = getStringAttr(PmdAttr.RIGID_ID); + this.helper.addRigidId(rigidId, this.currentRigid); + + String behavior = getStringAttr(PmdAttr.BEHAVIOR); + RigidBehaviorType type = RigidBehaviorType.valueOf(behavior); + this.currentRigid.setBehaviorType(type); + + return; + } + + /** + * rigidタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.RIGID) + void closeRigid(){ + List rigidInfoList = getPmdModel().getRigidList(); + rigidInfoList.add(this.currentRigid); + + this.currentRigid = null; + + return; + } + + /** + * i18nTextタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.I18N_NAME) + void openI18nText(){ + I18nText i18nName; + if(this.currentRigid != null){ + i18nName = this.currentRigid.getRigidName(); + }else if(this.currentJoint != null){ + i18nName = this.currentJoint.getJointName(); + }else{ + assert false; + throw new AssertionError(); + } + + String lang = getStringAttr(PmdAttr.LANG); + String name = getStringAttr(PmdAttr.NAME); + + i18nName.setI18nText(lang, name); + + return; + } + + /** + * linkedBoneタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.LINKED_BONE) + void openLinkedBone(){ + String boneIdRef = getStringAttr(PmdAttr.BONE_IDREF); + BoneInfo linkedBone = this.helper.findBoneId(boneIdRef); + this.currentRigid.setLinkedBone(linkedBone); + + return; + } + + /** + * rigidShapeSphereタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID_SHAPE_SPHERE) + void openRigidShapeSphere(){ + RigidShape shape = this.currentRigid.getRigidShape(); + + shape.setShapeType(RigidShapeType.SPHERE); + + float radius = getFloatAttr(PmdAttr.RADIUS); + shape.setRadius(radius); + + return; + } + + /** + * rigidShapeBoxタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID_SHAPE_BOX) + void openRigidShapeBox(){ + RigidShape shape = this.currentRigid.getRigidShape(); + + shape.setShapeType(RigidShapeType.BOX); + + float width = getFloatAttr(PmdAttr.WIDTH); + float height = getFloatAttr(PmdAttr.HEIGHT); + float depth = getFloatAttr(PmdAttr.DEPTH); + + shape.setWidth(width); + shape.setHeight(height); + shape.setDepth(depth); + + return; + } + + /** + * rigidShapeCapsuleタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID_SHAPE_CAPSULE) + void openRigidShapeCapsule(){ + RigidShape shape = this.currentRigid.getRigidShape(); + + shape.setShapeType(RigidShapeType.CAPSULE); + + float height = getFloatAttr(PmdAttr.HEIGHT); + float radius = getFloatAttr(PmdAttr.RADIUS); + + shape.setHeight(height); + shape.setRadius(radius); + + return; + } + + /** + * positionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.POSITION) + void openPosition(){ + MkPos3D pos; + if(this.currentRigid != null){ + pos = this.currentRigid.getPosition(); + }else if(this.currentJoint != null){ + pos = this.currentJoint.getPosition(); + }else{ + assert false; + throw new AssertionError(); + } + + float x = getFloatAttr(PmdAttr.X); + float y = getFloatAttr(PmdAttr.Y); + float z = getFloatAttr(PmdAttr.Z); + + pos.setPosition(x, y, z); + + return; + } + + /** + * radRotationタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RAD_ROTATION) + void openRadRotation(){ + Rad3d rad; + if(this.currentRigid != null){ + rad = this.currentRigid.getRotation(); + }else if(this.currentJoint != null){ + rad = this.currentJoint.getRotation(); + }else{ + assert false; + throw new AssertionError(); + } + + float xRad = getFloatAttr(PmdAttr.X_RAD); + float yRad = getFloatAttr(PmdAttr.Y_RAD); + float zRad = getFloatAttr(PmdAttr.Z_RAD); + + rad.setXRad(xRad); + rad.setYRad(yRad); + rad.setZRad(zRad); + + return; + } + + /** + * dynamicsタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.DYNAMICS) + void openDynamics(){ + + float mass = getFloatAttr(PmdAttr.MASS); + float dampingPosition = getFloatAttr(PmdAttr.DAMPING_POSITION); + float dampingRotation = getFloatAttr(PmdAttr.DAMPING_ROTATION); + float restitution = getFloatAttr(PmdAttr.RESTITUTION); + float friction = getFloatAttr(PmdAttr.FRICTION); + + DynamicsInfo dynamics = this.currentRigid.getDynamicsInfo(); + + dynamics.setMass(mass); + dynamics.setDampingPosition(dampingPosition); + dynamics.setDampingRotation(dampingRotation); + dynamics.setRestitution(restitution); + dynamics.setFriction(friction); + + return; + } + + /** + * throughRigidGroupタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.THROUGH_RIGID_GROUP) + void openThroughRigidGroup(){ + String rigidGroupIdRef = + getStringAttr(PmdAttr.RIGID_GROUP_IDREF); + + this.helper.addThroughRigidGroupIdRef(this.currentRigid, + rigidGroupIdRef ); + + return; + } + + /** + * rigidGroupタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID_GROUP) + void openRigidGroup(){ + RigidGroup rigidGroup = new RigidGroup(); + this.currentRigidGroup = rigidGroup; + + String rigidGroupId = getStringAttr(PmdAttr.RIGID_GROUP_ID); + + this.helper.addRigidGroupId(rigidGroupId, this.currentRigidGroup); + + return; + } + + /** + * rigidGroupタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.RIGID_GROUP) + void closeRigidGroup(){ + List rigidGroupList = getPmdModel().getRigidGroupList(); + rigidGroupList.add(this.currentRigidGroup); + + this.currentRigidGroup = null; + + return; + } + + /** + * rigidGroupMemberタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.RIGID_GROUP_MEMBER) + void openRigidGroupMember(){ + String rigidIdRef = getStringAttr(PmdAttr.RIGID_IDREF); + + RigidInfo member = this.helper.findRigidId(rigidIdRef); + + List memberList = this.currentRigidGroup.getRigidList(); + memberList.add(member); + member.setRigidGroup(this.currentRigidGroup); + + return; + } + + /** + * rigidGroupListタグ終了の通知を受け取る。 + * 剛体グループ総数が定員に満たない場合は自動追加される。 + */ + @CloseXmlMark(PmdTag.RIGID_GROUP_LIST) + void closeRigidGroupList(){ + + this.helper.resolveThroughRigidGroupIdRef(); + + List rigidGroupList = getPmdModel().getRigidGroupList(); + + while(rigidGroupList.size() < RigidGroup.MAX_RIGID_GROUP){ + RigidGroup group = new RigidGroup(); + rigidGroupList.add(group); + } + + ListUtil.assignIndexedSerial(rigidGroupList); + + return; + } + + /** + * jointタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.JOINT) + void openJoint(){ + this.currentJoint = new JointInfo(); + + String name = getStringAttr(PmdAttr.NAME); + I18nText jointName = this.currentJoint.getJointName(); + jointName.setPrimaryText(name); + + return; + } + + /** + * jointタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.JOINT) + void closeJoint(){ + List jointList = getPmdModel().getJointList(); + jointList.add(this.currentJoint); + + this.currentJoint = null; + + return; + } + + /** + * jointedRigidPairタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.JOINTED_RIGID_PAIR) + void openJointedRigidPair(){ + String rigidIdRef1 = getStringAttr(PmdAttr.RIGID_IDREF_1); + String rigidIdRef2 = getStringAttr(PmdAttr.RIGID_IDREF_2); + + RigidInfo rigidA = this.helper.findRigidId(rigidIdRef1); + RigidInfo rigidB = this.helper.findRigidId(rigidIdRef2); + + this.currentJoint.setRigidPair(rigidA, rigidB); + + return; + } + + /** + * limitPositionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.LIMIT_POSITION) + void openLimitPosition(){ + float xFrom = getFloatAttr(PmdAttr.X_FROM); + float xTo = getFloatAttr(PmdAttr.X_TO); + + float yFrom = getFloatAttr(PmdAttr.Y_FROM); + float yTo = getFloatAttr(PmdAttr.Y_TO); + + float zFrom = getFloatAttr(PmdAttr.Z_FROM); + float zTo = getFloatAttr(PmdAttr.Z_TO); + + TripletRange limitPos = this.currentJoint.getPositionRange(); + limitPos.setXRange(xFrom, xTo); + limitPos.setYRange(yFrom, yTo); + limitPos.setZRange(zFrom, zTo); + + return; + } + + /** + * limitRotationタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.LIMIT_ROTATION) + void openLimitRotation(){ + float xFrom = getFloatAttr(PmdAttr.X_FROM); + float xTo = getFloatAttr(PmdAttr.X_TO); + + float yFrom = getFloatAttr(PmdAttr.Y_FROM); + float yTo = getFloatAttr(PmdAttr.Y_TO); + + float zFrom = getFloatAttr(PmdAttr.Z_FROM); + float zTo = getFloatAttr(PmdAttr.Z_TO); + + TripletRange limitRot = this.currentJoint.getRotationRange(); + limitRot.setXRange(xFrom, xTo); + limitRot.setYRange(yFrom, yTo); + limitRot.setZRange(zFrom, zTo); + + return; + } + + /** + * elasticPositionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.ELASTIC_POSITION) + void openElasticPosition(){ + float x = getFloatAttr(PmdAttr.X); + float y = getFloatAttr(PmdAttr.Y); + float z = getFloatAttr(PmdAttr.Z); + + MkPos3D pos = this.currentJoint.getElasticPosition(); + pos.setPosition(x, y, z); + + return; + } + + /** + * elasticRotationタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.ELASTIC_ROTATION) + void openElasticRotation(){ + float xDeg = getFloatAttr(PmdAttr.X_DEG); + float yDeg = getFloatAttr(PmdAttr.Y_DEG); + float zDeg = getFloatAttr(PmdAttr.Z_DEG); + + Deg3d rot = this.currentJoint.getElasticRotation(); + rot.setXDeg(xDeg); + rot.setYDeg(yDeg); + rot.setZDeg(zDeg); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxListener.java new file mode 100644 index 0000000..96e4974 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxListener.java @@ -0,0 +1,247 @@ +/* + * PMD-SAX element listsner + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.EnumMap; +import java.util.LinkedList; +import java.util.Map; +import javax.xml.bind.DatatypeConverter; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import org.xml.sax.Attributes; + +/** + * XML要素出現の通知受信部の共通実装。 + */ +class SaxListener { + + private final Map openDispatcher; + private final Map closeDispatcher; + + private PmdModel pmdModel = null; + private Attributes currentAttribute = null; + + + /** + * コンストラクタ。 + */ + protected SaxListener(){ + super(); + + Class thisClass = this.getClass(); + this.openDispatcher = getOpenDispatcher(thisClass); + this.closeDispatcher = getCloseDispatcher(thisClass); + + return; + } + + + /** + * 指定された注釈がマークされたインスタンスメソッド群を返す。 + * @param klass クラス + * @param filter 注釈 + * @return インスタンスメソッド群 + */ + private static Collection filtMethod(Class klass, + Class filter ){ + Collection result = new LinkedList(); + + for(Method method : klass.getDeclaredMethods()){ + int modifiers = method.getModifiers(); + if(Modifier.isStatic(modifiers)) continue; + if(Modifier.isPrivate(modifiers)) continue; + if(method.getParameterTypes().length > 0) continue; + + Annotation anno = method.getAnnotation(filter); + if(anno == null) continue; + + result.add(method); + } + + return result; + } + + /** + * 注釈でマークされた開始タグ通知用ディスパッチテーブルを返す。 + * @param klass 対象クラス + * @return ディスパッチテーブル + */ + private static Map getOpenDispatcher(Class klass){ + Map result = + new EnumMap(PmdTag.class); + + for(Method method : filtMethod(klass, OpenXmlMark.class)){ + Annotation anno = method.getAnnotation(OpenXmlMark.class); + OpenXmlMark mark = (OpenXmlMark) anno; + PmdTag tag = mark.value(); + result.put(tag, method); + } + + return result; + } + + /** + * 注釈でマークされた終了タグ通知用ディスパッチテーブルを返す。 + * @param klass 対象クラス + * @return ディスパッチテーブル + */ + private static Map getCloseDispatcher(Class klass){ + Map result = + new EnumMap(PmdTag.class); + + for(Method method : filtMethod(klass, CloseXmlMark.class)){ + Annotation anno = method.getAnnotation(CloseXmlMark.class); + CloseXmlMark mark = (CloseXmlMark) anno; + PmdTag tag = mark.value(); + result.put(tag, method); + } + + return result; + } + + + /** + * ディスパッチテーブルに従いディスパッチする。 + * @param map ディスパッチテーブル + * @param tag タグ種 + * @return ディスパッチが行われなければfalse + */ + private boolean dispatch(Map map, PmdTag tag){ + Method method = map.get(tag); + if(method == null) return false; + + try{ + method.invoke(this); + }catch(IllegalAccessException ex){ + assert false; + }catch(InvocationTargetException ex){ + Throwable cause = ex.getTargetException(); + if(cause instanceof RuntimeException){ + throw (RuntimeException) cause; + }else if(cause instanceof Error){ + throw (Error) cause; + } + } + + return true; + } + + /** + * 開始タグ登場を通知する。 + * @param tag タグ種別 + * @param attr 属性群 + * @return ディスパッチが行われなければfalse + */ + boolean openDispatch(PmdTag tag, Attributes attr){ + this.currentAttribute = attr; + return dispatch(this.openDispatcher, tag); + } + + /** + * 終了タグ登場を通知する。 + * @param tag タグ種別 + * @return ディスパッチが行われなければfalse + */ + boolean closeDispatch(PmdTag tag){ + return dispatch(this.closeDispatcher, tag); + } + + /** + * CharData出現の通知。 + * @param ch 文字配列 + * @param start 開始位置 + * @param length 長さ + */ + void addCharData(char[] ch, int start, int length){ + return; + } + + /** + * ビルド対象オブジェクトの登録。 + * @param model ビルド対象オブジェクト + * @throws NullPointerException 引数がnull + */ + void setPmdModel(PmdModel model) throws NullPointerException{ + if(model == null) throw new NullPointerException(); + this.pmdModel = model; + return; + } + + /** + * ビルド対象オブジェクトの取得。 + * @return ビルド対象オブジェクト。未登録の場合はnull。 + */ + protected PmdModel getPmdModel(){ + return this.pmdModel; + } + + /** + * xsd:string型属性値の読み込み。 + * @param attr 属性名 + * @return 属性値。該当する属性が無ければnull。 + * @see "http://www.w3.org/TR/xmlschema-2/#string" + */ + protected String getStringAttr(PmdAttr attr){ + String attrName = attr.attr(); + String result = this.currentAttribute.getValue(attrName); + return result; + } + + /** + * xsd:boolean型属性値の読み込み。 + * @param attr 属性名 + * @return 属性値。 + * @throws IllegalArgumentException boolean型表記ではない + * @see "http://www.w3.org/TR/xmlschema-2/#boolean" + */ + protected boolean getBooleanAttr(PmdAttr attr) + throws IllegalArgumentException{ + String attrName = attr.attr(); + String attrVal = this.currentAttribute.getValue(attrName); + boolean bVal; + bVal = DatatypeConverter.parseBoolean(attrVal); + return bVal; + } + + /** + * xsd:float型属性値の読み込み。 + * @param attr 属性名 + * @return 属性値。 + * @throws NumberFormatException float型表記ではない + * @see "http://www.w3.org/TR/xmlschema-2/#float" + */ + protected float getFloatAttr(PmdAttr attr) + throws NumberFormatException { + String attrName = attr.attr(); + String attrVal = this.currentAttribute.getValue(attrName); + float fVal; + fVal = DatatypeConverter.parseFloat(attrVal); + return fVal; + } + + /** + * xsd:int型属性値の読み込み。 + * @param attr 属性名 + * @return 属性値。 + * @throws NumberFormatException int型表記ではない + * @see "http://www.w3.org/TR/xmlschema-2/#int" + */ + protected int getIntAttr(PmdAttr attr) + throws NumberFormatException { + String attrName = attr.attr(); + String attrVal = this.currentAttribute.getValue(attrName); + int iVal; + iVal = DatatypeConverter.parseInt(attrVal); + return iVal; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMaterialListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMaterialListener.java new file mode 100644 index 0000000..c8745ee --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMaterialListener.java @@ -0,0 +1,244 @@ +/* + * material listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.awt.Color; +import java.util.List; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.pmd.model.Material; +import jp.sfjp.mikutoga.pmd.model.ShadeInfo; +import jp.sfjp.mikutoga.pmd.model.ToonMap; + +/* + + materialList + + material + + i18nName + + diffuse + + specular + + ambient + + toon + + textureFile + + spheremapFile + + toonMap + + toonDef +*/ + +/** + * マテリアル関連のXML要素出現イベントを受信する。 + */ +class SaxMaterialListener extends SaxListener{ + + private static final char BS_CHAR = (char) 0x005c; + private static final char YEN_CHAR = (char) 0x00a5; + private static final String BS_TXT = Character.toString(BS_CHAR); + private static final String YEN_TXT = Character.toString(YEN_CHAR); + + private static final int TOON_IDX_NONE = 255; + + + private final RefHelper helper; + + private Material currentMaterial = null; + + + /** + * コンストラクタ。 + * @param helper 参照ヘルパ + */ + SaxMaterialListener(RefHelper helper) { + super(); + this.helper = helper; + return; + } + + + /** + * 日本語Windows用ファイル名の正規化を行う。 + * 文字U+00A5は文字U-005Cに変換される。 + * @param txt 変換元文字列 + * @return 正規化された文字列 + */ + private static String xferBslash(String txt){ + String result; + result = txt.replace(YEN_TXT, BS_TXT); + return result; + } + + + /** + * materialタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.MATERIAL) + void openMaterial(){ + this.currentMaterial = new Material(); + + String name = getStringAttr(PmdAttr.NAME); + boolean showEdge = getBooleanAttr(PmdAttr.SHOW_EDGE); + String surfaceGroupIdRef = + getStringAttr(PmdAttr.SURFACE_GROUP_IDREF); + + I18nText i18nName = this.currentMaterial.getMaterialName(); + if(name != null){ + i18nName.setPrimaryText(name); + } + + this.currentMaterial.setEdgeAppearance(showEdge); + + this.currentMaterial.getShadeInfo().setToonIndex(TOON_IDX_NONE); + + this.helper.addSurfaceGroupIdRef(this.currentMaterial, + surfaceGroupIdRef); + + return; + } + + /** + * materialタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.MATERIAL) + void closeMaterial(){ + List materialList = getPmdModel().getMaterialList(); + materialList.add(this.currentMaterial); + this.currentMaterial = null; + + return; + } + + /** + * i18nTextタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.I18N_NAME) + void openI18nText(){ + String lang = getStringAttr(PmdAttr.LANG); + String name = getStringAttr(PmdAttr.NAME); + + I18nText materialName = this.currentMaterial.getMaterialName(); + materialName.setI18nText(lang, name); + + return; + } + + /** + * diffuseタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.DIFFUSE) + void openDiffuse(){ + float rCol = getFloatAttr(PmdAttr.R); + float gCol = getFloatAttr(PmdAttr.G); + float bCol = getFloatAttr(PmdAttr.B); + float alpha = getFloatAttr(PmdAttr.ALPHA); + + Color color = new Color(rCol, gCol, bCol, alpha); + + this.currentMaterial.setDiffuseColor(color); + + return; + } + + /** + * specularタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.SPECULAR) + void openSpecular(){ + float rCol = getFloatAttr(PmdAttr.R); + float gCol = getFloatAttr(PmdAttr.G); + float bCol = getFloatAttr(PmdAttr.B); + + Color color = new Color(rCol, gCol, bCol); + float shine = getFloatAttr(PmdAttr.SHININESS); + + this.currentMaterial.setSpecularColor(color); + this.currentMaterial.setShininess(shine); + + return; + } + + /** + * ambientタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.AMBIENT) + void openAmbient(){ + float rCol = getFloatAttr(PmdAttr.R); + float gCol = getFloatAttr(PmdAttr.G); + float bCol = getFloatAttr(PmdAttr.B); + + Color color = new Color(rCol, gCol, bCol); + + this.currentMaterial.setAmbientColor(color); + + return; + } + + /** + * toonタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.TOON) + void openToon(){ + String toonFileIdRef = getStringAttr(PmdAttr.TOONFILE_IDREF); + + this.helper.addToonFileIdRef(this.currentMaterial, toonFileIdRef); + + return; + } + + /** + * textureFileタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.TEXTURE_FILE) + void openTextureFile(){ + String fileName = getStringAttr(PmdAttr.WINFILE_NAME); + fileName = xferBslash(fileName); + + ShadeInfo shadeInfo = this.currentMaterial.getShadeInfo(); + shadeInfo.setTextureFileName(fileName); + + return; + } + + /** + * spheremapFileタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.SPHEREMAP_FILE) + void openSphemapFile(){ + String fileName = getStringAttr(PmdAttr.WINFILE_NAME); + fileName = xferBslash(fileName); + + ShadeInfo shadeInfo = this.currentMaterial.getShadeInfo(); + shadeInfo.setSpheremapFileName(fileName); + + return; + } + + /** + * toonDefタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.TOON_DEF) + void openToonDef(){ + String toonFileId = getStringAttr(PmdAttr.TOONFILE_ID); + int index = getIntAttr(PmdAttr.INDEX); + String fileName = getStringAttr(PmdAttr.WINFILE_NAME); + fileName = xferBslash(fileName); + + ToonMap toonMap = getPmdModel().getToonMap(); + toonMap.setIndexedToon(index, fileName); + + this.helper.addToonIdx(toonFileId, index); + + return; + } + + /** + * toonMapタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.TOON_MAP) + void closeToonMap(){ + this.helper.resolveToonIdx(); + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxModelListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxModelListener.java new file mode 100644 index 0000000..99432e0 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxModelListener.java @@ -0,0 +1,128 @@ +/* + * model listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import jp.sfjp.mikutoga.corelib.I18nText; + +/* + + pmdModel + + i18nName + + description + + license + + credits + + meta + ..... +*/ + +/** + * モデル関連のXML要素出現イベントを受信する。 + */ +class SaxModelListener extends SaxListener{ + + private String currentLang = null; + private StringBuilder currentBredTxt = null; + + + /** + * コンストラクタ。 + */ + SaxModelListener() { + super(); + return; + } + + + /** + * CharData出現の通知。 + * @param ch 文字配列 + * @param start 開始位置 + * @param length 長さ + */ + @Override + void addCharData(char[] ch, int start, int length){ + if(this.currentBredTxt == null) return; + + for(int idx = 0; idx < length; idx++){ + int pos = start + idx; + char chData = ch[pos]; + if(chData == '\n') continue; + if(chData == '\r') continue; + this.currentBredTxt.append(chData); + } + + return; + } + + /** + * pmdModelタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.PMD_MODEL) + void openPmdModel(){ + I18nText modelName = getPmdModel().getModelName(); + + String name = getStringAttr(PmdAttr.NAME); + modelName.setPrimaryText(name); + + return; + } + + /** + * i18nTextタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.I18N_NAME) + void openI18nText(){ + String lang = getStringAttr(PmdAttr.LANG); + String name = getStringAttr(PmdAttr.NAME); + + I18nText modelName = getPmdModel().getModelName(); + modelName.setI18nText(lang, name); + + return; + } + + /** + * descriptionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.DESCRIPTION) + void openDescription(){ + this.currentLang = getStringAttr(PmdAttr.LANG); + this.currentBredTxt = new StringBuilder(); + return; + } + + /** + * descriptionタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.DESCRIPTION) + void closeDescription(){ + String bredText = this.currentBredTxt.toString(); + + I18nText desc = getPmdModel().getDescription(); + if(this.currentLang == null){ + desc.setPrimaryText(bredText); + }else{ + desc.setI18nText(this.currentLang, bredText); + } + + this.currentLang = null; + this.currentBredTxt = null; + + return; + } + + /** + * brタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.BR) + void openBr(){ + if(this.currentBredTxt == null) return; + this.currentBredTxt.append('\n'); + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMorphListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMorphListener.java new file mode 100644 index 0000000..c118b28 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxMorphListener.java @@ -0,0 +1,144 @@ +/* + * morph listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import jp.sfjp.mikutoga.corelib.I18nText; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.pmd.MorphType; +import jp.sfjp.mikutoga.pmd.model.ListUtil; +import jp.sfjp.mikutoga.pmd.model.MorphPart; +import jp.sfjp.mikutoga.pmd.model.MorphVertex; + +/* + + morphList + + morph + + i18nName + + morphVertex +*/ + +/** + * モーフ関連のXML要素出現イベントを受信する。 + */ +class SaxMorphListener extends SaxListener{ + + private final RefHelper helper; + + private MorphPart currentMorph = null; + + + /** + * コンストラクタ。 + * @param helper 参照ヘルパ + */ + SaxMorphListener(RefHelper helper) { + super(); + this.helper = helper; + return; + } + + + /** + * morphListタグ終了の通知を受け取る。 + * 各モーフは0番ではなく1番から採番される。 + * 0番は暗黙のBASEモーフ。 + */ + @CloseXmlMark(PmdTag.MORPH_LIST) + void closeMorphList(){ + Map> morphMap = + getPmdModel().getMorphMap(); + List tempList = new LinkedList(); + + tempList.addAll(morphMap.get(MorphType.EYEBROW)); + tempList.addAll(morphMap.get(MorphType.EYE)); + tempList.addAll(morphMap.get(MorphType.LIP)); + tempList.addAll(morphMap.get(MorphType.EXTRA)); + + MorphPart baseDummy = new MorphPart(); + tempList.add(0, baseDummy); // BASE dummy + + ListUtil.assignIndexedSerial(tempList); + + return; + } + + /** + * morphタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.MORPH) + void openMorph(){ + this.currentMorph = new MorphPart(); + + String name = getStringAttr(PmdAttr.NAME); + I18nText morphName = this.currentMorph.getMorphName(); + morphName.setPrimaryText(name); + + String type = getStringAttr(PmdAttr.TYPE); + MorphType morphType = MorphType.valueOf(type); + this.currentMorph.setMorphType(morphType); + + return; + } + + /** + * morphタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.MORPH) + void closeMorph(){ + Map> morphMap = + getPmdModel().getMorphMap(); + + MorphType morphType = this.currentMorph.getMorphType(); + List morphList = morphMap.get(morphType); + morphList.add(this.currentMorph); + + this.currentMorph = null; + + return; + } + + /** + * i18nTextタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.I18N_NAME) + void openI18nText(){ + String lang = getStringAttr(PmdAttr.LANG); + String name = getStringAttr(PmdAttr.NAME); + + I18nText morphName = this.currentMorph.getMorphName(); + morphName.setI18nText(lang, name); + + return; + } + + /** + * morphVertexタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.MORPH_VERTEX) + void openMorphVertex(){ + MorphVertex morphVertex = new MorphVertex(); + + String vertexIdRef = getStringAttr(PmdAttr.VERTEX_IDREF); + this.helper.addMorphVertexIdRef(morphVertex, vertexIdRef); + + float xOff = getFloatAttr(PmdAttr.XOFF); + float yOff = getFloatAttr(PmdAttr.YOFF); + float zOff = getFloatAttr(PmdAttr.ZOFF); + MkPos3D offset = morphVertex.getOffset(); + offset.setPosition(xOff, yOff, zOff); + + List morphVertexList = + this.currentMorph.getMorphVertexList(); + morphVertexList.add(morphVertex); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxShapeListener.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxShapeListener.java new file mode 100644 index 0000000..fbf689d --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/SaxShapeListener.java @@ -0,0 +1,212 @@ +/* + * shape listener from XML + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.List; +import jp.sfjp.mikutoga.math.MkPos2D; +import jp.sfjp.mikutoga.math.MkPos3D; +import jp.sfjp.mikutoga.math.MkVec3D; +import jp.sfjp.mikutoga.pmd.model.BoneInfo; +import jp.sfjp.mikutoga.pmd.model.ListUtil; +import jp.sfjp.mikutoga.pmd.model.Surface; +import jp.sfjp.mikutoga.pmd.model.Vertex; + +/* + + surfaceGroupList + + surfaceGroup + + surface + + vertexList + + vertex + + position + + normal + + uvMap + + skinning +*/ + +/** + * 形状関連のXML要素出現イベントを受信する。 + */ +class SaxShapeListener extends SaxListener{ + + private final RefHelper helper; + + private String currentSurfaceGroupId = null; + private Vertex currentVertex = null; + + + /** + * コンストラクタ。 + * @param helper 参照ヘルパ + */ + SaxShapeListener(RefHelper helper) { + super(); + this.helper = helper; + return; + } + + + /** + * surfaceGroupListタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.SURFACE_GROUP_LIST) + void closeSurfaceGroupList(){ + this.helper.resolveMaterialSurfaceGroupId(); + return; + } + + /** + * surfaceGroupタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.SURFACE_GROUP) + void openSurfaceGroup(){ + String surfaceGroupId = getStringAttr(PmdAttr.SURFACE_GROUP_ID); + this.currentSurfaceGroupId = surfaceGroupId; + + return; + } + + /** + * surfaceGroupタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.SURFACE_GROUP) + void closeSurfaceGroup(){ + this.currentSurfaceGroupId = null; + return; + } + + /** + * surfaceタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.SURFACE) + void openSurface(){ + Surface surface = new Surface(); + + String vtxIdRef1 = getStringAttr(PmdAttr.VERTEX_IDREF_1); + String vtxIdRef2 = getStringAttr(PmdAttr.VERTEX_IDREF_2); + String vtxIdRef3 = getStringAttr(PmdAttr.VERTEX_IDREF_3); + + this.helper.addSurfaceGroup(this.currentSurfaceGroupId, surface); + this.helper.addSurfaceVertex(surface, + vtxIdRef1, + vtxIdRef2, + vtxIdRef3 ); + + List surfaceList = getPmdModel().getSurfaceList(); + surfaceList.add(surface); + + return; + } + + /** + * vertexタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.VERTEX) + void openVertex(){ + this.currentVertex = new Vertex(); + + String vtxId = getStringAttr(PmdAttr.VERTEX_ID); + boolean showEdge = getBooleanAttr(PmdAttr.SHOW_EDGE); + + this.currentVertex.setEdgeAppearance(showEdge); + + this.helper.addVertexId(vtxId, this.currentVertex); + + return; + } + + /** + * vertexタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.VERTEX) + void closeVertex(){ + List vertexList = getPmdModel().getVertexList(); + + vertexList.add(this.currentVertex); + + this.currentVertex = null; + + return; + } + + /** + * positionタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.POSITION) + void openPosition(){ + float x = getFloatAttr(PmdAttr.X); + float y = getFloatAttr(PmdAttr.Y); + float z = getFloatAttr(PmdAttr.Z); + + MkPos3D pos = this.currentVertex.getPosition(); + pos.setPosition(x, y, z); + + return; + } + + /** + * normalタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.NORMAL) + void openNormal(){ + float x = getFloatAttr(PmdAttr.X); + float y = getFloatAttr(PmdAttr.Y); + float z = getFloatAttr(PmdAttr.Z); + + MkVec3D normal = this.currentVertex.getNormal(); + normal.setVector(x, y, z); + + return; + } + + /** + * uvMapタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.UV_MAP) + void openUvMap(){ + float u = getFloatAttr(PmdAttr.U); + float v = getFloatAttr(PmdAttr.V); + + MkPos2D pos = this.currentVertex.getUVPosition(); + pos.setPosition(u, v); + + return; + } + + /** + * skinningタグ開始の通知を受け取る。 + */ + @OpenXmlMark(PmdTag.SKINNING) + void openSkinning(){ + String boneIdRef1 = getStringAttr(PmdAttr.BONE_IDREF_1); + String boneIdRef2 = getStringAttr(PmdAttr.BONE_IDREF_2); + BoneInfo bone1 = this.helper.findBoneId(boneIdRef1); + BoneInfo bone2 = this.helper.findBoneId(boneIdRef2); + + int weightBalance = getIntAttr(PmdAttr.WEIGHT_BALANCE); + + this.currentVertex.setBonePair(bone1, bone2); + this.currentVertex.setWeightA(weightBalance); + + return; + } + + /** + * vertexListタグ終了の通知を受け取る。 + */ + @CloseXmlMark(PmdTag.VERTEX_LIST) + void closeVertexList(){ + this.helper.resolveMorphVertexIdRef(); + this.helper.resolveSurfaceVertexIdRef(); + + List vertexList = getPmdModel().getVertexList(); + ListUtil.assignIndexedSerial(vertexList); + + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema101009.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema101009.java similarity index 95% rename from src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema101009.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema101009.java index 137ba02..3746859 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema101009.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema101009.java @@ -5,11 +5,11 @@ * Copyright(c) 2010 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.xml; +package jp.sfjp.mikutoga.pmd.model.xml; import java.net.URI; import java.net.URISyntaxException; -import jp.sourceforge.mikutoga.xml.LocalXmlResource; +import jp.sfjp.mikutoga.xml.LocalXmlResource; /** * 101009形式XML各種リソースの定義。 diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema130128.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema130128.java similarity index 95% rename from src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema130128.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema130128.java index c27f542..6b99257 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/Schema130128.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/Schema130128.java @@ -5,11 +5,11 @@ * Copyright(c) 2013 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.xml; +package jp.sfjp.mikutoga.pmd.model.xml; import java.net.URI; import java.net.URISyntaxException; -import jp.sourceforge.mikutoga.xml.LocalXmlResource; +import jp.sfjp.mikutoga.xml.LocalXmlResource; /** * 130128形式XML各種リソースの定義。 diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlHandler.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlHandler.java new file mode 100644 index 0000000..f8db09c --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlHandler.java @@ -0,0 +1,249 @@ +/* + * xml to pmd SAX Handler + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.util.EnumMap; +import java.util.Map; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; + +/** + * XMLモデルファイルパース用SAXハンドラ。 + *

下位リスナに各種通知が振り分けられる。 + */ +class XmlHandler implements ContentHandler{ + + private final Map listenerMap; + private SaxListener currentListener = null; + + private PmdModel pmdModel = null; + + private String nspfx = ""; + private String nsuri = null; + + + /** + * コンストラクタ。 + */ + XmlHandler(){ + super(); + + RefHelper helper = new RefHelper(); + SaxListener modelListener = new SaxModelListener(); + SaxListener materialListener = new SaxMaterialListener(helper); + SaxListener boneListener = new SaxBoneListener(helper); + SaxListener morphListener = new SaxMorphListener(helper); + SaxListener dynamicsListener = new SaxDynamicsListener(helper); + SaxListener shapeListener = new SaxShapeListener(helper); + + this.listenerMap = new EnumMap(PmdTag.class); + this.listenerMap.put(PmdTag.PMD_MODEL, modelListener); + this.listenerMap.put(PmdTag.MATERIAL_LIST, materialListener); + this.listenerMap.put(PmdTag.BONE_LIST, boneListener); + this.listenerMap.put(PmdTag.MORPH_LIST, morphListener); + this.listenerMap.put(PmdTag.RIGID_LIST, dynamicsListener); + this.listenerMap.put(PmdTag.SURFACE_GROUP_LIST, shapeListener); + + return; + } + + + /** + * ビルド対象のモデルを返す。 + * @return ビルド対象のモデル。ビルド前ならnull + */ + PmdModel getPmdModel(){ + return this.pmdModel; + } + + /** + * {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void startDocument() throws SAXException{ + this.pmdModel = new PmdModel(); + + for(SaxListener listener : this.listenerMap.values()){ + listener.setPmdModel(this.pmdModel); + } + + return; + } + + /** + * {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void endDocument() throws SAXException{ + assert this.pmdModel != null; + this.currentListener = null; + return; + } + + /** + * {@inheritDoc} + * @param prefix {@inheritDoc} + * @param uri {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + if( Schema101009.NS_PMDXML.equals(uri) + || Schema130128.NS_PMDXML.equals(uri) ){ + this.nspfx = prefix; + this.nsuri = uri; + } + return; + } + + /** + * {@inheritDoc} + * @param prefix {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void endPrefixMapping(String prefix) throws SAXException { + if(prefix.equals(this.nspfx)){ + this.nspfx = ""; + this.nsuri = null; + } + return; + } + + /** + * {@inheritDoc} + * @param uri {@inheritDoc} + * @param localName {@inheritDoc} + * @param qName {@inheritDoc} + * @param attr {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void startElement(String uri, + String localName, + String qName, + Attributes attr) + throws SAXException { + if( ! this.nsuri.equals(uri) ) return; + + PmdTag tag = PmdTag.parse(localName); + if(tag == null) return; + + switchListener(tag); + + if(this.currentListener == null) return; + this.currentListener.openDispatch(tag, attr); + + return; + } + + /** + * タグ出現に従い通知リスナを切り替える。 + * @param tag タグ種別 + */ + private void switchListener(PmdTag tag){ + SaxListener newListener = this.listenerMap.get(tag); + if(newListener == null) return; + + this.currentListener = newListener; + + return; + } + + /** + * {@inheritDoc} + * @param uri {@inheritDoc} + * @param localName {@inheritDoc} + * @param qName {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void endElement(String uri, String localName, String qName) + throws SAXException { + if( ! this.nsuri.equals(uri) ) return; + + PmdTag tag = PmdTag.parse(localName); + if(tag == null) return; + + if(this.currentListener != null){ + this.currentListener.closeDispatch(tag); + } + + return; + } + + /** + * {@inheritDoc} + * @param locator {@inheritDoc} + */ + @Override + public void setDocumentLocator(Locator locator){ + // NOTHING + return; + } + + /** + * {@inheritDoc} + * @param target {@inheritDoc} + * @param data {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void processingInstruction(String target, String data) + throws SAXException { + // NOTHING + return; + } + + /** + * {@inheritDoc} + * @param ch {@inheritDoc} + * @param start {@inheritDoc} + * @param length {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + if(this.currentListener == null) return; + this.currentListener.addCharData(ch, start, length); + return; + } + + /** + * {@inheritDoc} + * @param ch {@inheritDoc} + * @param start {@inheritDoc} + * @param length {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + // NOTHING + return; + } + + /** + * {@inheritDoc} + * @param name {@inheritDoc} + * @throws SAXException {@inheritDoc} + */ + @Override + public void skippedEntity(String name) throws SAXException{ + // NOTHING + return; + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlModelFileType.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlModelFileType.java similarity index 94% rename from src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlModelFileType.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlModelFileType.java index 981e693..555b283 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlModelFileType.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlModelFileType.java @@ -5,7 +5,7 @@ * Copyright(c) 2013 MikuToga Partners */ -package jp.sfjp.mikutoga.pmd.xml; +package jp.sfjp.mikutoga.pmd.model.xml; /** * XMLファイルスキーマ種別。 diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlPmdLoader.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlPmdLoader.java new file mode 100644 index 0000000..c7a3411 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/XmlPmdLoader.java @@ -0,0 +1,76 @@ +/* + * xml to pmd loader + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd.model.xml; + +import java.io.IOException; +import jp.sfjp.mikutoga.pmd.model.PmdModel; +import jp.sfjp.mikutoga.xml.TogaXmlException; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * XMLモデルファイルを読み込むためのローダ。 + */ +public class XmlPmdLoader { + + private static final String SAXFEATURES_NAMESPACES = + "http://xml.org/sax/features/namespaces"; + + private final XMLReader reader; + + + /** + * コンストラクタ。 + *

XMLリーダは名前空間をサポートしていなければならない。 + * @param reader XMLリーダ + * @throws NullPointerException 引数がnull + * @throws SAXException 機能不足のXMLリーダが渡された + */ + public XmlPmdLoader(XMLReader reader) + throws NullPointerException, SAXException { + super(); + + if(reader == null) throw new NullPointerException(); + if( ! reader.getFeature(SAXFEATURES_NAMESPACES) ){ + throw new SAXException(); + } + + this.reader = reader; + + return; + } + + + /** + * XMLのパースを開始する。 + * @param source XML入力 + * @return モデルデータ + * @throws SAXException 構文エラー + * @throws IOException 入力エラー + * @throws TogaXmlException 構文エラー + */ + public PmdModel parse(InputSource source) + throws SAXException, IOException, TogaXmlException{ + XmlHandler saxHandler = new XmlHandler(); + this.reader.setContentHandler(saxHandler); + + try{ + this.reader.parse(source); + }catch(SAXException e){ + Throwable cause = e.getCause(); + if(cause instanceof TogaXmlException){ + throw (TogaXmlException) cause; + } + throw e; + } + + return saxHandler.getPmdModel(); + } + +} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/package-info.java b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/package-info.java similarity index 54% rename from src/main/java/jp/sfjp/mikutoga/pmd/xml/package-info.java rename to src/main/java/jp/sfjp/mikutoga/pmd/model/xml/package-info.java index 848c3f0..25adb4b 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/package-info.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd/model/xml/package-info.java @@ -6,9 +6,9 @@ */ /** - * PMDモデル内容をXMLで出力するためのライブラリ。 + * PMDモデル内容をXMLで入出力するためのライブラリ。 */ -package jp.sfjp.mikutoga.pmd.xml; +package jp.sfjp.mikutoga.pmd.model.xml; /* EOF */ diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/PmdXmlExporter.java b/src/main/java/jp/sfjp/mikutoga/pmd/xml/PmdXmlExporter.java deleted file mode 100644 index e149129..0000000 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/PmdXmlExporter.java +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * pmd-xml exporter - * - * License : The MIT License - * Copyright(c) 2010 MikuToga Partners - */ - -package jp.sfjp.mikutoga.pmd.xml; - -import java.awt.Color; -import java.io.IOException; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import jp.sfjp.mikutoga.corelib.I18nText; -import jp.sfjp.mikutoga.math.MkPos2D; -import jp.sfjp.mikutoga.math.MkPos3D; -import jp.sfjp.mikutoga.math.MkVec3D; -import jp.sfjp.mikutoga.pmd.BoneType; -import jp.sfjp.mikutoga.pmd.Deg3d; -import jp.sfjp.mikutoga.pmd.MorphType; -import jp.sfjp.mikutoga.pmd.Rad3d; -import jp.sfjp.mikutoga.pmd.RigidShapeType; -import jp.sfjp.mikutoga.pmd.TripletRange; -import jp.sfjp.mikutoga.pmd.model.BoneGroup; -import jp.sfjp.mikutoga.pmd.model.BoneInfo; -import jp.sfjp.mikutoga.pmd.model.DynamicsInfo; -import jp.sfjp.mikutoga.pmd.model.IKChain; -import jp.sfjp.mikutoga.pmd.model.JointInfo; -import jp.sfjp.mikutoga.pmd.model.Material; -import jp.sfjp.mikutoga.pmd.model.MorphPart; -import jp.sfjp.mikutoga.pmd.model.MorphVertex; -import jp.sfjp.mikutoga.pmd.model.PmdModel; -import jp.sfjp.mikutoga.pmd.model.RigidGroup; -import jp.sfjp.mikutoga.pmd.model.RigidInfo; -import jp.sfjp.mikutoga.pmd.model.RigidShape; -import jp.sfjp.mikutoga.pmd.model.SerialNumbered; -import jp.sfjp.mikutoga.pmd.model.ShadeInfo; -import jp.sfjp.mikutoga.pmd.model.Surface; -import jp.sfjp.mikutoga.pmd.model.ToonMap; -import jp.sfjp.mikutoga.pmd.model.Vertex; -import jp.sourceforge.mikutoga.xml.BasicXmlExporter; -import jp.sourceforge.mikutoga.xml.XmlResourceResolver; - -/** - * 101009形式XMLでPMDモデルデータを出力する。 - */ -public class PmdXmlExporter extends BasicXmlExporter{ - - private static final String TOP_COMMENT = - " MikuMikuDance\n" - + " model-data(*.pmd) on XML"; - - /** 改行文字列 CR。 */ - private static final String CR = "\r"; // 0x0d - /** 改行文字列 LF。 */ - private static final String LF = "\n"; // 0x0a - /** 改行文字列 CRLF。 */ - private static final String CRLF = CR + LF; // 0x0d, 0x0a - - private static final String PFX_SURFACEGROUP = "sg"; - private static final String PFX_TOONFILE = "tf"; - private static final String PFX_VERTEX = "vtx"; - private static final String PFX_BONE = "bn"; - private static final String PFX_RIGID = "rd"; - private static final String PFX_RIGIDGROUP = "rg"; - - private static final String BONETYPE_COMMENT = - "Bone types:\n" - + "[0 : ROTATE : Rotate : 回転 :]\n" - + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n" - + "[2 : IK : IK : IK :]\n" - + "[3 : UNKNOWN : Unknown : 不明 :]\n" - + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n" - + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n" - + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n" - + "[7 : HIDDEN : Hidden : 非表示 :]\n" - + "[8 : TWIST : Twist : 捩り :]\n" - + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n"; - - private static final String MORPHTYPE_COMMENT = - "Morph types:\n" - + "[1 : EYEBROW : まゆ ]\n" - + "[2 : EYE : 目 ]\n" - + "[3 : LIP : リップ ]\n" - + "[4 : EXTRA : その他 ]\n"; - - private static final String RIGIDBEHAVIOR_COMMENT = - "Rigid behavior types:\n" - + "[0 : FOLLOWBONE : ボーン追従 ]\n" - + "[1 : ONLYDYNAMICS : 物理演算 ]\n" - + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n"; - - private static final Locale DEF_LOCALE = Locale.JAPANESE; - - - private String generator = null; - - private XmlModelFileType xmlType = XmlModelFileType.XML_101009; - - - /** - * コンストラクタ。 - */ - public PmdXmlExporter(){ - super(); - return; - } - - - /** - * 出力XMLファイル種別を返す。 - * @return ファイル種別 - */ - public XmlModelFileType getXmlFileType(){ - return this.xmlType; - } - - /** - * 出力XMLファイル種別を設定する。 - * @param type ファイル種別 - */ - public void setXmlFileType(XmlModelFileType type){ - switch(type){ - case XML_101009: - case XML_130128: - this.xmlType = type; - break; - case XML_AUTO: - this.xmlType = XmlModelFileType.XML_130128; - break; - default: - throw new IllegalArgumentException(); - } - - assert this.xmlType == XmlModelFileType.XML_101009 - || this.xmlType == XmlModelFileType.XML_130128; - - return; - } - - /** - * Generatorメタ情報を設定する。 - * @param generatorArg Generatorメタ情報。表示したくないときはnull - */ - public void setGenerator(String generatorArg){ - this.generator = generatorArg; - return; - } - - /** - * 任意の文字列がBasicLatin文字のみから構成されるか判定する。 - * @param seq 文字列 - * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue - */ - public static boolean hasOnlyBasicLatin(CharSequence seq){ - if(seq == null) return true; - int length = seq.length(); - for(int pos = 0; pos < length; pos++){ - char ch = seq.charAt(pos); - if(ch > 0x007f) return false; - } - return true; - } - - /** - * {@inheritDoc} - * @return {@inheritDoc} - * @throws IOException {@inheritDoc} - */ - @Override - public PmdXmlExporter ind() throws IOException{ - super.ind(); - return this; - } - - /** - * 文字参照によるエスケープを補佐するためのコメントを出力する。 - * @param seq 文字列 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putUnescapedComment(CharSequence seq) - throws IOException{ - if( ! isBasicLatinOnlyOut() ) return this; - if(hasOnlyBasicLatin(seq)) return this; - sp().putLineComment(seq); - return this; - } - - /** - * 多言語化された各種識別名を出力する。 - * プライマリ名は出力対象外。 - * @param text 多言語文字列 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putI18nName(I18nText text) throws IOException{ - for(String lang639 : text.lang639CodeList()){ - if(lang639.equals(I18nText.CODE639_PRIMARY)) continue; - String name = text.getI18nText(lang639); - ind().putRawText(""); - putUnescapedComment(name); - ln(); - } - return this; - } - - /** - * 番号付けされたID(IDREF)属性を出力する。 - * @param attrName 属性名 - * @param prefix IDプレフィクス - * @param num 番号 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName, - CharSequence prefix, - int num ) - throws IOException{ - putRawText(attrName).putRawText("=\""); - putRawText(prefix).putXsdInt(num); - putRawCh('"'); - return this; - } - - /** - * 番号付けされたID(IDREF)属性を出力する。 - * @param attrName 属性名 - * @param prefix IDプレフィクス - * @param numbered 番号付けされたオブジェクト - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName, - CharSequence prefix, - SerialNumbered numbered ) - throws IOException{ - putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber()); - return this; - } - - /** - * 位置情報を出力する。 - * @param position 位置情報 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putPosition(MkPos3D position) - throws IOException{ - putRawText(""); - return this; - } - - /** - * 姿勢情報(ラジアン)を出力する。 - * @param rotation 姿勢情報 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putRadRotation(Rad3d rotation) - throws IOException{ - putRawText(""); - return this; - } - - /** - * 多言語識別名属性のローカルな名前をコメント出力する。 - * @param name 多言語識別名 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putLocalNameComment(I18nText name) - throws IOException{ - String localName = name.getText(); - if(localName.isEmpty()){ - localName = "[NAMELESS]"; - } - ind().putLineComment(localName); - return this; - } - - /** - * 多言語識別名属性のプライマリな名前を出力する。 - * @param attrName 属性名 - * @param name 多言語識別名 - * @return this本体 - * @throws IOException 出力エラー - */ - protected PmdXmlExporter putPrimaryNameAttr(CharSequence attrName, - I18nText name) - throws IOException{ - String primaryName = name.getPrimaryText(); - putAttr(attrName, primaryName); - return this; - } - - /** - * PMDモデルデータをXML形式で出力する。 - * @param model PMDモデルデータ - * @param xmlOut XML出力先 - * @throws IOException 出力エラー - */ - public void putPmdModel(PmdModel model, Appendable xmlOut) - throws IOException{ - setAppendable(xmlOut); - - ind().putRawText("").ln(2); - - ind().putBlockComment(TOP_COMMENT).ln(2); - - I18nText modelName = model.getModelName(); - ind().putLocalNameComment(modelName).ln(); - ind().putRawText("").ln(2); - - putModelInfo(model).flush(); - putMetaInfo(model).flush(); - putMaterialList(model).flush(); - putToonMap(model).flush(); - putBoneList(model).flush(); - putBoneGroupList(model).flush(); - putIKChainList(model).flush(); - putMorphList(model).flush(); - putRigidList(model).flush(); - putRigidGroupList(model).flush(); - putJointList(model).flush(); - putSurfaceGroupList(model).flush(); - putVertexList(model).flush(); - - ind().putRawText("").ln(2); - ind().putRawText("").ln(); - - return; - } - - /** - * モデル基本情報を出力する。 - * @param model モデル情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putModelInfo(PmdModel model) - throws IOException{ - I18nText modelName = model.getModelName(); - putI18nName(modelName); - ln(); - - I18nText description = model.getDescription(); - for(String lang639 : description.lang639CodeList()){ - String descText = description.getI18nText(lang639); - putDescription(lang639, descText); - ln(); - } - - return this; - } - - /** - * モデル詳細テキストを出力する。 - * @param lang639 言語コード - * @param content 詳細内容 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putDescription(CharSequence lang639, - CharSequence content) - throws IOException{ - String text = content.toString(); - text = text.replace(CRLF, LF); - text = text.replace(CR, LF); - - ind().putRawText("").ln(); - - putBRedContent(text); - - ind().putRawText("").ln(); - - if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){ - putBlockComment(text); - } - - return this; - } - - /** - * break要素を含む要素内容を出力する。 - * 必要に応じてXML定義済み実体文字が割り振られた文字、 - * コントロールコード、および非BasicLatin文字がエスケープされる。 - * \nはbrタグに変換される。 - * @param content 内容 - * @return this本体 - * @throws IOException 出力エラー - */ - protected BasicXmlExporter putBRedContent(CharSequence content) - throws IOException{ - int length = content.length(); - - int startPos = 0; - - for(int idx = 0; idx < length; idx++){ - char ch = content.charAt(idx); - if(ch == '\n'){ - CharSequence seq = content.subSequence(startPos, idx); - putContent(seq).putRawText("
").ln(); - startPos = idx + 1; - } - } - - if(startPos < length){ - CharSequence seq = content.subSequence(startPos, length); - putContent(seq).ln(); - } - - return this; - } - - /** - * 各種メタ情報を出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putMetaInfo(PmdModel model) throws IOException{ - ind().putRawText("").ln(); - ind().putRawText("").ln(2); - - ind().putRawText("").ln(); - ind().putRawText("").ln(2); - - if(this.generator != null){ - ind().putRawText("").ln(); - } - - ind().putRawText("").ln(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * マテリアル素材一覧を出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putMaterialList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - int ct = 0; - boolean dumped = false; - List materialList = model.getMaterialList(); - for(Material material : materialList){ - if( ! dumped ) ln(); - putMaterial(material, ct++); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * マテリアル素材情報を出力する。 - * @param material マテリアル素材 - * @param no マテリアル通し番号 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putMaterial(Material material, int no) - throws IOException{ - String bool; - if(material.getEdgeAppearance()) bool = "true"; - else bool = "false"; - I18nText name = material.getMaterialName(); - String primary = name.getPrimaryText(); - String local = name.getText(); - - if(local != null && local.length() > 0){ - ind().putLineComment(local).ln(); - } - ind().putRawText(" 0){ - putAttr("name", primary).sp(); - } - - putAttr("showEdge", bool); - sp(); - putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no); - sp().putRawCh('>').ln(); - pushNest(); - - putI18nName(name); - - float[] rgba = new float[4]; - - Color diffuse = material.getDiffuseColor(); - diffuse.getRGBComponents(rgba); - ind().putRawText("").ln(); - - Color specular = material.getSpecularColor(); - specular.getRGBComponents(rgba); - float shininess = material.getShininess(); - ind().putRawText("").ln(); - - Color ambient = material.getAmbientColor(); - ambient.getRGBComponents(rgba); - ind().putRawText("").ln(); - - ShadeInfo shade = material.getShadeInfo(); - String textureFileName = shade.getTextureFileName(); - String spheremapFileName = shade.getSpheremapFileName(); - - if(shade.isValidToonIndex()){ - ind().putRawText(""); - String toonFileName = shade.getToonFileName(); - if(toonFileName != null && toonFileName.length() > 0){ - sp().putLineComment(toonFileName); - } - ln(); - } - - if(textureFileName != null && textureFileName.length() > 0){ - ind().putRawText("").ln(); - } - - if(spheremapFileName != null && spheremapFileName.length() > 0){ - ind().putRawText("").ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * トゥーンファイルマッピング情報を出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putToonMap(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - pushNest(); - - ToonMap map = model.getToonMap(); - for(int index = 0; index <= 9; index++){ - ind().putToon(map, index).ln(); - } - - popNest(); - ind().putRawText("").ln(2); - return this; - } - - /** - * 個別のトゥーンファイル情報を出力する。 - * @param map トゥーンマップ - * @param index インデックス値 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putToon(ToonMap map, int index) - throws IOException{ - putRawText(""); - putUnescapedComment(toonFile); - return this; - } - - /** - * サーフェイスグループリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putSurfaceGroupList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - int ct = 0; - boolean dumped = false; - List materialList = model.getMaterialList(); - for(Material material : materialList){ - List surfaceList = material.getSurfaceList(); - if( ! dumped ) ln(); - putSurfaceList(surfaceList, ct++); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のサーフェイスグループを出力する。 - * @param surfaceList サーフェイスのリスト - * @param index グループインデックス - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putSurfaceList(List surfaceList, - int index) - throws IOException{ - ind().putRawText("").ln(); - pushNest(); - - for(Surface surface : surfaceList){ - putSurface(surface); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のサーフェイスを出力する。 - * @param surface サーフェイス - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putSurface(Surface surface) - throws IOException{ - ind().putRawText("").ln(); - return this; - } - - /** - * 頂点リストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putVertexList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - boolean dumped = false; - List vertexList = model.getVertexList(); - for(Vertex vertex : vertexList){ - if( ! dumped ) ln(); - putVertex(vertex); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別の頂点情報を出力する。 - * @param vertex 頂点 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putVertex(Vertex vertex) - throws IOException{ - String bool; - if(vertex.getEdgeAppearance()) bool = "true"; - else bool = "false"; - - ind().putRawText("").ln(); - pushNest(); - - MkPos3D position = vertex.getPosition(); - ind().putPosition(position).ln(); - - MkVec3D normal = vertex.getNormal(); - ind().putRawText("").ln(); - - MkPos2D uvPos = vertex.getUVPosition(); - ind().putRawText("").ln(); - - BoneInfo boneA = vertex.getBoneA(); - BoneInfo boneB = vertex.getBoneB(); - int weight = vertex.getWeightA(); - ind().putRawText("").ln(); - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * ボーンリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putBoneList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - pushNest(); - - boolean dumped = false; - for(BoneInfo bone : model.getBoneList()){ - if( ! dumped ){ - ln().putBlockComment(BONETYPE_COMMENT).ln(); - } - putBone(bone); - dumped = true; - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のボーン情報を出力する。 - * @param bone ボーン情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putBone(BoneInfo bone) - throws IOException{ - I18nText i18nName = bone.getBoneName(); - BoneType type = bone.getBoneType(); - - StringBuilder boneComment = new StringBuilder(); - String boneName = i18nName.getText(); - if(boneName.isEmpty()){ - boneName = "[NAMELESS]"; - } - boneComment.append(boneName); - String typeName = type.getGuiName(DEF_LOCALE); - boneComment.append(" [").append(typeName).append(']'); - ind().putLineComment(boneComment.toString()).ln(); - - ind().putRawText("").ln(); - pushNest(); - - putI18nName(i18nName); - - MkPos3D position = bone.getPosition(); - ind().putPosition(position).ln(); - - BoneInfo srcBone = bone.getSrcBone(); - if(bone.getBoneType() == BoneType.LINKEDROT){ - ind().putRawText("").ln(); - }else if(srcBone != null){ - String iktag; - switch(getXmlFileType()){ - case XML_101009: - iktag = " "); - String ikBoneName = "Ref:" + srcBone.getBoneName().getText(); - putLineComment(ikBoneName); - ln(); - } - - BoneInfo prev = bone.getPrevBone(); - BoneInfo next = bone.getNextBone(); - - StringBuilder chainComment = new StringBuilder(); - if(prev != null){ - chainComment.append('[') - .append(prev.getBoneName().getPrimaryText()) - .append(']') - .append(" >>#"); - } - if(next != null){ - if(chainComment.length() <= 0) chainComment.append("#"); - chainComment.append(">> ") - .append('[') - .append(next.getBoneName().getPrimaryText()) - .append(']'); - } - if(chainComment.length() > 0){ - ln(); - ind().putLineComment(chainComment).ln(); - } - - ind().putRawText("").ln(); - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * ボーングループリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putBoneGroupList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - boolean dumped = false; - List groupList = model.getBoneGroupList(); - for(BoneGroup group : groupList){ - if(group.isDefaultBoneGroup()) continue; - if( ! dumped ) ln(); - putBoneGroup(group); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のボーングループ情報を出力する。 - * @param group ボーングループ情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putBoneGroup(BoneGroup group) - throws IOException{ - I18nText i18nName = group.getGroupName(); - - putLocalNameComment(i18nName).ln(); - ind().putRawText("").ln(); - pushNest(); - - putI18nName(i18nName); - - for(BoneInfo bone : group){ - ind().putRawText(" "); - String boneName = "Ref:" + bone.getBoneName().getText(); - putLineComment(boneName).ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * IKチェーンリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putIKChainList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - boolean dumped = false; - List chainList = model.getIKChainList(); - for(IKChain chain : chainList){ - if( ! dumped ) ln(); - putIKChain(chain); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のIKチェーン情報を出力する。 - * @param chain チェーン情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putIKChain(IKChain chain) - throws IOException{ - int depth = chain.getIKDepth(); - float weight = chain.getIKWeight(); - BoneInfo ikBone = chain.getIkBone(); - - ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln(); - ind().putRawText("").ln(); - pushNest(); - - for(BoneInfo bone : chain){ - ind().putRawText(" "); - putLineComment("Ref:" + bone.getBoneName().getText()); - ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * モーフリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putMorphList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - pushNest(); - - boolean dumped = false; - Map> morphMap = model.getMorphMap(); - for(MorphType type : MorphType.values()){ - if(type == MorphType.BASE) continue; - List partList = morphMap.get(type); - if(partList == null) continue; - for(MorphPart part : partList){ - if( ! dumped ){ - ln().putBlockComment(MORPHTYPE_COMMENT).ln(); - } - putMorphPart(part); - dumped = true; - } - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のモーフ情報を出力する。 - * @param part モーフ情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putMorphPart(MorphPart part) - throws IOException{ - I18nText i18nName = part.getMorphName(); - String primary = i18nName.getPrimaryText(); - - putLocalNameComment(i18nName).ln(); - ind().putRawText(""); - ln(); - pushNest(); - - putI18nName(i18nName); - - for(MorphVertex mvertex : part){ - MkPos3D offset = mvertex.getOffset(); - Vertex base = mvertex.getBaseVertex(); - - ind().putRawText(""); - ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 剛体リストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putRigidList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - pushNest(); - - boolean dumped = false; - for(RigidInfo rigid : model.getRigidList()){ - if( ! dumped ){ - ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln(); - } - putRigid(rigid); - dumped = true; - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別の剛体情報を出力する。 - * @param rigid 剛体情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putRigid(RigidInfo rigid) - throws IOException{ - BoneInfo linkedBone = rigid.getLinkedBone(); - I18nText i18nName = rigid.getRigidName(); - String primary = i18nName.getPrimaryText(); - - putLocalNameComment(i18nName).ln(); - ind().putRawText("").ln(); - pushNest(); - - putI18nName(i18nName); - - if(linkedBone != null){ - ind().putRawText(" "); - putLineComment("Ref:" + linkedBone.getBoneName().getText()); - ln(2); - } - - RigidShape shape = rigid.getRigidShape(); - putRigidShape(shape); - - MkPos3D position = rigid.getPosition(); - ind().putPosition(position).ln(); - - Rad3d rotation = rigid.getRotation(); - ind().putRadRotation(rotation).ln(); - - DynamicsInfo dynamics = rigid.getDynamicsInfo(); - putDynamics(dynamics).ln(); - - for(RigidGroup group : rigid.getThroughGroupColl()){ - ind().putRawText("").ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * 剛体形状を出力する。 - * @param shape 剛体形状 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putRigidShape(RigidShape shape) - throws IOException{ - RigidShapeType type = shape.getShapeType(); - - switch(type){ - case BOX: - ind().putRawText("").ln(); - - return this; - } - - /** - * 力学設定を出力する。 - * @param dynamics 力学設定 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putDynamics(DynamicsInfo dynamics) - throws IOException{ - ind().putRawText("").ln(); - - return this; - } - - /** - * 剛体グループリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putRigidGroupList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(2); - pushNest(); - - boolean singleLast = false; - for(RigidGroup group : model.getRigidGroupList()){ - List rigidList = group.getRigidList(); - if(singleLast && ! rigidList.isEmpty()){ - ln(); - } - ind().putRawText("").ln(); - singleLast = true; - continue; - } - putRawText(" >").ln(); - pushNest(); - - for(RigidInfo rigid : rigidList){ - ind().putRawText(""); - sp(); - putLineComment("Ref:" + rigid.getRigidName().getText()); - ln(); - } - - popNest(); - ind().putRawText("").ln(2); - singleLast = false; - } - - if(singleLast){ - ln(); - } - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - - /** - * ジョイントリストを出力する。 - * @param model モデルデータ - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putJointList(PmdModel model) - throws IOException{ - ind().putRawText("").ln(); - - pushNest(); - boolean dumped = false; - List jointList = model.getJointList(); - for(JointInfo joint : jointList){ - if( ! dumped ) ln(); - putJoint(joint); - dumped = true; - } - popNest(); - - ind().putRawText("").ln(2); - - return this; - } - - /** - * 個別のジョイント情報を出力する。 - * @param joint ジョイント情報 - * @return this本体 - * @throws IOException 出力エラー - */ - private PmdXmlExporter putJoint(JointInfo joint) - throws IOException{ - I18nText i18nName = joint.getJointName(); - - putLocalNameComment(i18nName).ln(); - ind().putRawText("").ln(); - pushNest(); - - putI18nName(i18nName); - - RigidInfo rigidA = joint.getRigidA(); - RigidInfo rigidB = joint.getRigidB(); - - ind(); - putLineComment("[" + rigidA.getRigidName().getText() + "]" - + " <=> [" + rigidB.getRigidName().getText() + "]"); - ln(); - - ind().putRawText("").ln(2); - - MkPos3D position = joint.getPosition(); - ind().putPosition(position).ln(); - - TripletRange posRange = joint.getPositionRange(); - ind().putRawText("").ln(2); - - Rad3d rotation = joint.getRotation(); - ind().putRadRotation(rotation).ln(); - TripletRange rotRange = joint.getRotationRange(); - ind().putRawText("").ln(2); - - MkPos3D elaPosition = joint.getElasticPosition(); - ind().putRawText("").ln(); - - Deg3d elaRotation = joint.getElasticRotation(); - ind().putRawText("").ln(2); - - popNest(); - ind().putRawText("").ln(2); - - return this; - } - -} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlLoader.java b/src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlLoader.java deleted file mode 100644 index d0160db..0000000 --- a/src/main/java/jp/sfjp/mikutoga/pmd/xml/XmlLoader.java +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * xml loader - * - * License : The MIT License - * Copyright(c) 2010 MikuToga Partners - */ - -package jp.sfjp.mikutoga.pmd.xml; - -import java.awt.Color; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import javax.xml.parsers.DocumentBuilder; -import jp.sfjp.mikutoga.corelib.I18nText; -import jp.sfjp.mikutoga.math.MkPos2D; -import jp.sfjp.mikutoga.math.MkPos3D; -import jp.sfjp.mikutoga.math.MkVec3D; -import jp.sfjp.mikutoga.pmd.BoneType; -import jp.sfjp.mikutoga.pmd.Deg3d; -import jp.sfjp.mikutoga.pmd.MorphType; -import jp.sfjp.mikutoga.pmd.Rad3d; -import jp.sfjp.mikutoga.pmd.RigidBehaviorType; -import jp.sfjp.mikutoga.pmd.RigidShapeType; -import jp.sfjp.mikutoga.pmd.TripletRange; -import jp.sfjp.mikutoga.pmd.model.BoneGroup; -import jp.sfjp.mikutoga.pmd.model.BoneInfo; -import jp.sfjp.mikutoga.pmd.model.DynamicsInfo; -import jp.sfjp.mikutoga.pmd.model.IKChain; -import jp.sfjp.mikutoga.pmd.model.JointInfo; -import jp.sfjp.mikutoga.pmd.model.ListUtil; -import jp.sfjp.mikutoga.pmd.model.Material; -import jp.sfjp.mikutoga.pmd.model.MorphPart; -import jp.sfjp.mikutoga.pmd.model.MorphVertex; -import jp.sfjp.mikutoga.pmd.model.PmdModel; -import jp.sfjp.mikutoga.pmd.model.RigidGroup; -import jp.sfjp.mikutoga.pmd.model.RigidInfo; -import jp.sfjp.mikutoga.pmd.model.RigidShape; -import jp.sfjp.mikutoga.pmd.model.ShadeInfo; -import jp.sfjp.mikutoga.pmd.model.Surface; -import jp.sfjp.mikutoga.pmd.model.ToonMap; -import jp.sfjp.mikutoga.pmd.model.Vertex; -import jp.sourceforge.mikutoga.xml.DomNsUtils; -import jp.sourceforge.mikutoga.xml.DomUtils; -import jp.sourceforge.mikutoga.xml.TogaXmlException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -/** - * XML形式でのモデルファイルを読み込む。 - */ -public class XmlLoader { - - private static final String ERR_INVROOT = - "invalid root element[{0}]"; - private static final String ERR_UKVER = - "unknown schema version[{0}]"; - - - private PmdModel model; - - private final Map toonIdxMap = - new HashMap(); - private final Map boneMap = - new HashMap(); - private final Map vertexMap = - new HashMap(); - private final Map> surfaceGroupMap = - new HashMap>(); - private final Map rigidMap = - new HashMap(); - private final Map rigidGroupMap = - new HashMap(); - - private String rootNamespace = Schema130128.NS_PMDXML; - private XmlModelFileType fileType = XmlModelFileType.XML_AUTO; - - - /** - * コンストラクタ。 - */ - public XmlLoader(){ - super(); - return; - } - - - /** - * 要素からxsd:string型属性値を読み取る。 - * @param elem 要素 - * @param attrName 属性名 - * @return 文字列 - * @throws TogaXmlException 属性値が見つからなかった。 - */ - private static String getStringAttr(Element elem, String attrName) - throws TogaXmlException{ - return DomUtils.getStringAttr(elem, attrName); - } - - /** - * 要素からxsd:boolean型属性値を読み取る。 - * @param elem 要素 - * @param attrName 属性名 - * @return 真ならtrue - * @throws TogaXmlException 属性値が見つからなかった。 - */ - private static boolean getBooleanAttr(Element elem, String attrName) - throws TogaXmlException{ - return DomUtils.getBooleanAttr(elem, attrName); - } - - /** - * 要素からxsd:integer型属性値を読み取る。 - * @param elem 要素 - * @param attrName 属性名 - * @return int値 - * @throws TogaXmlException 属性値が見つからなかった。 - */ - private static int getIntegerAttr(Element elem, String attrName) - throws TogaXmlException{ - return DomUtils.getIntegerAttr(elem, attrName); - } - - /** - * 要素からxsd:float型属性値を読み取る。 - * @param elem 要素 - * @param attrName 属性名 - * @return float値 - * @throws TogaXmlException 属性値が見つからなかった。 - */ - private static float getFloatAttr(Element elem, String attrName) - throws TogaXmlException{ - return DomUtils.getFloatAttr(elem, attrName); - } - - /** - * 要素から日本語Windows用ファイル名を属性値として読み取る。 - * 念のため文字U+00A5は文字U-005Cに変換される。 - * @param elem 要素 - * @param attrName 属性名 - * @return ファイル名 - * @throws TogaXmlException 属性値が見つからなかった。 - */ - private static String getSjisFileNameAttr(Element elem, String attrName) - throws TogaXmlException{ - return DomUtils.getSjisFileNameAttr(elem, attrName); - } - - /** - * brタグで区切られた文字列内容(Mixed content)を - * 改行付き文字列に変換する。 - * brタグはその出現回数だけ\nに変換される。 - * 生文字列コンテンツ中の\n,\rは削除される。 - * 改行文字以外のホワイトスペースは保持される。 - * @param parent br要素及び文字列コンテンツを含む要素 - * @return 変換された文字列 - */ - private static String getBRedContent(Element parent){ - StringBuilder result = new StringBuilder(); - - for(Node node = parent.getFirstChild(); - node != null; - node = node.getNextSibling() ){ - - switch(node.getNodeType()){ - case Node.ELEMENT_NODE: - Element elem = (Element) node; - if("br".equals(elem.getTagName())){ - result.append('\n'); - } - break; - case Node.TEXT_NODE: - case Node.CDATA_SECTION_NODE: - String content = node.getTextContent(); - content = content.replace("\r", ""); - content = content.replace("\n", ""); - result.append(content); - break; - default: - break; - } - } - - return result.toString(); - } - - - /** - * パース中のXMLファイル種別を返す。 - * @return ファイル種別 - */ - private XmlModelFileType getFileType(){ - return this.fileType; - } - - /** - * パース中のXMLファイル種別を設定する。 - * @param type 具体的なファイル種別 - */ - private void setFileType(XmlModelFileType type){ - if( type != XmlModelFileType.XML_101009 - && type != XmlModelFileType.XML_130128 ){ - throw new IllegalArgumentException(); - } - this.fileType = type; - return; - } - - /** - * ルート要素の名前空間URIを返す。 - * @return 名前空間URI。nullなら名前空間が無いと見なされる - */ - private String getRootNamespace(){ - return this.rootNamespace; - } - - /** - * ルート要素の名前空間URIを設定する。 - * @param name 名前空間URI。nullなら名前空間が無いと見なされる - */ - private void setRootNamespace(String name){ - this.rootNamespace = name; - return; - } - - /** - * 指定された名前の子要素を1つだけ返す。 - * @param parent 親要素 - * @param tagName 子要素名 - * @return 子要素 - * @throws TogaXmlException 1つも見つからなかった - */ - private Element getChild(Element parent, String tagName) - throws TogaXmlException{ - String ns = getRootNamespace(); - Element result = DomNsUtils.getFirstChild(parent, ns, tagName); - return result; - } - - /** - * 親要素が指定された名前の子要素を持つか判定する。 - * @param parent 親要素 - * @param tagName 子要素名 - * @return 指定名の子要素が存在すればtrue - */ - private boolean hasChild(Element parent, String tagName){ - String ns = getRootNamespace(); - return DomNsUtils.hasChild(parent, ns, tagName); - } - - /** - * 指定された名前の子要素のforeachを返す。 - * @param parent 親要素 - * @param childTag 子要素名 - * @return 子要素のforeach - */ - private Iterable eachChild(Element parent, - String childTag){ - String ns = getRootNamespace(); - return DomNsUtils.getEachChild(parent, ns, childTag); - } - - /** - * 多言語名を取得する。 - * @param baseElement 元要素 - * @param text 多言語名格納先 - * @throws TogaXmlException あるべき属性が存在しない。 - */ - private void buildI18nName(Element baseElement, I18nText text) - throws TogaXmlException{ - String primaryText; - primaryText = getStringAttr(baseElement, "name"); - text.setPrimaryText(primaryText); - - for(Element i18nNameElem : eachChild(baseElement, "i18nName")){ - String lang = getStringAttr(i18nNameElem, "lang"); - String name = getStringAttr(i18nNameElem, "name"); - if("en".equals(lang)){ - text.setGlobalText(name); - }else{ - text.setI18nText(lang, text); - } - } - - return; - } - - /** - * XMLのパースを開始する。 - * @param builder ドキュメントビルダ - * @param source XML入力 - * @return モデルデータ - * @throws SAXException 構文エラー - * @throws IOException 入力エラー - * @throws TogaXmlException 構文エラー - */ - public PmdModel parse(DocumentBuilder builder, InputSource source) - throws SAXException, IOException, TogaXmlException{ - Document document = builder.parse(source); - PmdModel result = parse(document); - return result; - } - - /** - * XMLのパースを開始する。 - * @param document DOMドキュメント - * @return モデルデータ - * @throws TogaXmlException 構文エラー - */ - public PmdModel parse(Document document) - throws TogaXmlException{ - this.model = new PmdModel(); - - Element pmdModelElem = document.getDocumentElement(); - String namespace = pmdModelElem.getNamespaceURI(); - setRootNamespace(namespace); - - buildBasicInfo(pmdModelElem); - - buildBoneList(pmdModelElem); - buildVertexList(pmdModelElem); - buildSurfaceList(pmdModelElem); - - buildToonMap(pmdModelElem); - buildMaterialList(pmdModelElem); - buildIkChainList(pmdModelElem); - buildMorphList(pmdModelElem); - buildBoneGroupList(pmdModelElem); - - buildRigidList(pmdModelElem); - buildRigidGroupList(pmdModelElem); - resolveThroughRigidGroup(pmdModelElem); - - buildJointList(pmdModelElem); - - return this.model; - } - - /** - * DOMからモデル基本情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildBasicInfo(Element pmdModelElem) - throws TogaXmlException{ - if( ! DomNsUtils.hasNsLocalNameElem(pmdModelElem, - getRootNamespace(), - "pmdModel") ){ - String tagName = pmdModelElem.getTagName(); - String msg = MessageFormat.format(ERR_INVROOT, tagName); - throw new TogaXmlException(msg); - } - - String version = getStringAttr(pmdModelElem, "schemaVersion"); - if(Schema101009.VER_PMDXML.equals(version)){ - setFileType(XmlModelFileType.XML_101009); - }else if(Schema130128.VER_PMDXML.equals(version)){ - setFileType(XmlModelFileType.XML_130128); - }else{ - String msg = MessageFormat.format(ERR_UKVER, version); - throw new TogaXmlException(msg); - } - - I18nText modelName = this.model.getModelName(); - buildI18nName(pmdModelElem, modelName); - - String primaryDescription = null; - String globalDescription = null; - for(Element descriptionElem : - eachChild(pmdModelElem, "description")){ - String descriptionText = getBRedContent(descriptionElem); - if( ! descriptionElem.hasAttribute("lang") ){ - primaryDescription = descriptionText; - }else{ - String lang = getStringAttr(descriptionElem, "lang"); - if(lang.equals("ja")){ - primaryDescription = descriptionText; - }else if(lang.equals("en")){ - globalDescription = descriptionText; - } - } - } - - I18nText description = this.model.getDescription(); - description.setPrimaryText(primaryDescription); - description.setGlobalText(globalDescription); - - return; - } - - /** - * DOMからボーンリスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildBoneList(Element pmdModelElem) - throws TogaXmlException{ - Element boneListElem = getChild(pmdModelElem, "boneList"); - - List boneList = this.model.getBoneList(); - - for(Element boneElem : eachChild(boneListElem, "bone")){ - BoneInfo boneInfo = new BoneInfo(); - boneList.add(boneInfo); - - I18nText boneName = boneInfo.getBoneName(); - buildI18nName(boneElem, boneName); - - String boneType = getStringAttr(boneElem, "type"); - BoneType type = BoneType.valueOf(boneType); - boneInfo.setBoneType(type); - - String boneId = getStringAttr(boneElem, "boneId"); - this.boneMap.put(boneId, boneInfo); - - Element positionElem = getChild(boneElem, "position"); - float xPos = getFloatAttr(positionElem, "x"); - float yPos = getFloatAttr(positionElem, "y"); - float zPos = getFloatAttr(positionElem, "z"); - MkPos3D position = boneInfo.getPosition(); - position.setXpos(xPos); - position.setYpos(yPos); - position.setZpos(zPos); - } - - ListUtil.assignIndexedSerial(boneList); - - Iterator bit = boneList.iterator(); - for(Element boneElem : eachChild(boneListElem, "bone")){ - BoneInfo boneInfo = bit.next(); - - if(hasChild(boneElem, "ikBone")){ // 101009 only - Element ikBoneElem = getChild(boneElem, "ikBone"); - String ikBoneId = getStringAttr(ikBoneElem, "boneIdRef"); - BoneInfo ikBone = this.boneMap.get(ikBoneId); - boneInfo.setSrcBone(ikBone); - }else if(hasChild(boneElem, "sourceBone")){ // 130128 only - Element srcBoneElem = getChild(boneElem, "sourceBone"); - String srcBoneId = getStringAttr(srcBoneElem, "boneIdRef"); - BoneInfo srcBone = this.boneMap.get(srcBoneId); - boneInfo.setSrcBone(srcBone); - }else if(hasChild(boneElem, "rotationRatio")){ - Element rotElem = getChild(boneElem, "rotationRatio"); - int ratio = getIntegerAttr(rotElem, "ratio"); - boneInfo.setRotationRatio(ratio); - } - - Element boneChainElem = getChild(boneElem, "boneChain"); - if(boneChainElem.hasAttribute("prevBoneIdRef")){ - String prevId = getStringAttr(boneChainElem, "prevBoneIdRef"); - BoneInfo prevBone = this.boneMap.get(prevId); - boneInfo.setPrevBone(prevBone); - } - if(boneChainElem.hasAttribute("nextBoneIdRef")){ - String nextId = getStringAttr(boneChainElem, "nextBoneIdRef"); - BoneInfo nextBone = this.boneMap.get(nextId); - boneInfo.setNextBone(nextBone); - } - } - - return; - } - - /** - * DOMから頂点リスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildVertexList(Element pmdModelElem) - throws TogaXmlException{ - Element vertexListElem = getChild(pmdModelElem, "vertexList"); - - List vertexList = this.model.getVertexList(); - - for(Element vertexElem : eachChild(vertexListElem, "vertex")){ - Vertex vertex = new Vertex(); - vertexList.add(vertex); - - String vertexId = getStringAttr(vertexElem, "vtxId"); - this.vertexMap.put(vertexId, vertex); - - boolean showEdge = getBooleanAttr(vertexElem, "showEdge"); - vertex.setEdgeAppearance(showEdge); - - float xVal; - float yVal; - float zVal; - - Element positionElem = getChild(vertexElem, "position"); - xVal = getFloatAttr(positionElem, "x"); - yVal = getFloatAttr(positionElem, "y"); - zVal = getFloatAttr(positionElem, "z"); - MkPos3D position = vertex.getPosition(); - position.setXpos(xVal); - position.setYpos(yVal); - position.setZpos(zVal); - - Element normalElem = getChild(vertexElem, "normal"); - xVal = getFloatAttr(normalElem, "x"); - yVal = getFloatAttr(normalElem, "y"); - zVal = getFloatAttr(normalElem, "z"); - MkVec3D normal = vertex.getNormal(); - normal.setXVal(xVal); - normal.setYVal(yVal); - normal.setZVal(zVal); - - Element uvElem = getChild(vertexElem, "uvMap"); - float uVal = getFloatAttr(uvElem, "u"); - float vVal = getFloatAttr(uvElem, "v"); - MkPos2D uv = vertex.getUVPosition(); - uv.setXpos(uVal); - uv.setYpos(vVal); - - Element skinningElem = getChild(vertexElem, "skinning"); - String boneId1 = getStringAttr(skinningElem, "boneIdRef1"); - String boneId2 = getStringAttr(skinningElem, "boneIdRef2"); - int weight = getIntegerAttr(skinningElem, "weightBalance"); - BoneInfo boneA = this.boneMap.get(boneId1); - BoneInfo boneB = this.boneMap.get(boneId2); - vertex.setBonePair(boneA, boneB); - vertex.setWeightA(weight); - } - - ListUtil.assignIndexedSerial(vertexList); - - return; - } - - /** - * DOMからポリゴンリスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildSurfaceList(Element pmdModelElem) - throws TogaXmlException{ - Element surfaceGroupListElem = - getChild(pmdModelElem, "surfaceGroupList"); - - for(Element surfaceGroupElem : - eachChild(surfaceGroupListElem, "surfaceGroup") ){ - - String groupId = - getStringAttr(surfaceGroupElem, "surfaceGroupId"); - List surfaceList = buildSurface(surfaceGroupElem); - - this.surfaceGroupMap.put(groupId, surfaceList); - } - - return; - } - - /** - * DOMからポリゴン情報を組み立てる。 - * @param surfaceGroupElem surfaceGroup要素 - * @return ポリゴンリスト - * @throws TogaXmlException 構文エラー - */ - private List buildSurface(Element surfaceGroupElem) - throws TogaXmlException{ - List result = new ArrayList(); - - for(Element surfaceElem : eachChild(surfaceGroupElem, "surface")){ - Surface surface = new Surface(); - result.add(surface); - - String id1 = getStringAttr(surfaceElem, "vtxIdRef1"); - String id2 = getStringAttr(surfaceElem, "vtxIdRef2"); - String id3 = getStringAttr(surfaceElem, "vtxIdRef3"); - - Vertex vertex1 = this.vertexMap.get(id1); - Vertex vertex2 = this.vertexMap.get(id2); - Vertex vertex3 = this.vertexMap.get(id3); - - surface.setTriangle(vertex1, vertex2, vertex3); - } - - return result; - } - - /** - * DOMからトゥーンマップ情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildToonMap(Element pmdModelElem) - throws TogaXmlException{ - ToonMap toonMap = this.model.getToonMap(); - - Element toonMapElem = getChild(pmdModelElem, "toonMap"); - - for(Element toonDefElem : eachChild(toonMapElem, "toonDef")){ - String toonFileId = getStringAttr(toonDefElem, "toonFileId"); - int toonIndex = getIntegerAttr(toonDefElem, "index"); - String toonFile = getSjisFileNameAttr(toonDefElem, "winFileName"); - - toonMap.setIndexedToon(toonIndex, toonFile); - this.toonIdxMap.put(toonFileId, toonIndex); - } - - return; - } - - /** - * DOMからマテリアル情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildMaterialList(Element pmdModelElem) - throws TogaXmlException{ - Element materialListElem = - getChild(pmdModelElem, "materialList"); - - List surfaceList = this.model.getSurfaceList(); - List materialList = this.model.getMaterialList(); - - for(Element materialElem : eachChild(materialListElem, "material")){ - Material material = new Material(); - materialList.add(material); - - material.getShadeInfo().setToonMap(this.model.getToonMap()); - - String surfaceGroupId = - getStringAttr(materialElem, "surfaceGroupIdRef"); - List surfaceGroup = - this.surfaceGroupMap.get(surfaceGroupId); - surfaceList.addAll(surfaceGroup); - material.getSurfaceList().addAll(surfaceGroup); - - boolean hasEdge = getBooleanAttr(materialElem, "showEdge"); - material.setEdgeAppearance(hasEdge); - - ShadeInfo shadeInfo = material.getShadeInfo(); - - int toonIdx; - if(hasChild(materialElem, "toon")){ - Element toonElem = getChild(materialElem, "toon"); - String toonId = getStringAttr(toonElem, "toonFileIdRef"); - toonIdx = this.toonIdxMap.get(toonId); - }else{ - toonIdx = 255; - } - shadeInfo.setToonIndex(toonIdx); - - if(hasChild(materialElem, "textureFile")){ - Element textureFileElem = - getChild(materialElem, "textureFile"); - String textureFile = - getSjisFileNameAttr(textureFileElem, "winFileName"); - shadeInfo.setTextureFileName(textureFile); - } - - if(hasChild(materialElem, "spheremapFile")){ - Element spheremapFileElem = - getChild(materialElem, "spheremapFile"); - String spheremapFile = - getSjisFileNameAttr(spheremapFileElem, "winFileName"); - shadeInfo.setSpheremapFileName(spheremapFile); - } - - float red; - float green; - float blue; - - Element diffuseElem = getChild(materialElem, "diffuse"); - red = getFloatAttr(diffuseElem, "r"); - green = getFloatAttr(diffuseElem, "g"); - blue = getFloatAttr(diffuseElem, "b"); - float alpha = getFloatAttr(diffuseElem, "alpha"); - Color diffuse = new Color(red, green, blue, alpha); - material.setDiffuseColor(diffuse); - - Element specularElem = getChild(materialElem, "specular"); - red = getFloatAttr(specularElem, "r"); - green = getFloatAttr(specularElem, "g"); - blue = getFloatAttr(specularElem, "b"); - float shininess = getFloatAttr(specularElem, "shininess"); - Color specular = new Color(red, green, blue); - material.setSpecularColor(specular); - material.setShininess(shininess); - - Element ambientElem = getChild(materialElem, "ambient"); - red = getFloatAttr(ambientElem, "r"); - green = getFloatAttr(ambientElem, "g"); - blue = getFloatAttr(ambientElem, "b"); - Color ambient = new Color(red, green, blue); - material.setAmbientColor(ambient); - } - - return; - } - - /** - * DOMからIKチェーンリスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildIkChainList(Element pmdModelElem) - throws TogaXmlException{ - Element ikChainListElem = - getChild(pmdModelElem, "ikChainList"); - - List ikChainList = this.model.getIKChainList(); - - for(Element ikChainElem : eachChild(ikChainListElem, "ikChain")){ - IKChain ikChain = new IKChain(); - ikChainList.add(ikChain); - - String ikBoneIdRef = getStringAttr(ikChainElem, "ikBoneIdRef"); - int rucursiveDepth = - getIntegerAttr(ikChainElem, "recursiveDepth"); - float weight = getFloatAttr(ikChainElem, "weight"); - - BoneInfo ikBone = this.boneMap.get(ikBoneIdRef); - ikChain.setIkBone(ikBone); - ikChain.setIKDepth(rucursiveDepth); - ikChain.setIKWeight(weight); - - List chainList = ikChain.getChainedBoneList(); - - for(Element orderElem : eachChild(ikChainElem, "chainOrder")){ - String boneIdRef = getStringAttr(orderElem, "boneIdRef"); - BoneInfo chaindBone = this.boneMap.get(boneIdRef); - chainList.add(chaindBone); - } - } - - return; - } - - /** - * DOMからモーフリスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildMorphList(Element pmdModelElem) - throws TogaXmlException{ - Element morphListElem = - getChild(pmdModelElem, "morphList"); - - Map> morphMap = this.model.getMorphMap(); - - for(Element morphElem : eachChild(morphListElem, "morph")){ - MorphPart morphPart = new MorphPart(); - - I18nText name = morphPart.getMorphName(); - buildI18nName(morphElem, name); - - String type = getStringAttr(morphElem, "type"); - MorphType morphType = MorphType.valueOf(type); - morphPart.setMorphType(morphType); - - List morphVertexList = - morphPart.getMorphVertexList(); - - for(Element morphVertexElem - : eachChild(morphElem, "morphVertex")){ - String vtxIdRef = getStringAttr(morphVertexElem, "vtxIdRef"); - Vertex baseVertex = this.vertexMap.get(vtxIdRef); - float xOff = getFloatAttr(morphVertexElem, "xOff"); - float yOff = getFloatAttr(morphVertexElem, "yOff"); - float zOff = getFloatAttr(morphVertexElem, "zOff"); - - MorphVertex morphVertex = new MorphVertex(); - morphVertex.setBaseVertex(baseVertex); - MkPos3D position = morphVertex.getOffset(); - position.setXpos(xOff); - position.setYpos(yOff); - position.setZpos(zOff); - - morphVertexList.add(morphVertex); - } - - morphMap.get(morphType).add(morphPart); - } - - List serialList = new LinkedList(); - MorphPart baseDummy = new MorphPart(); - serialList.add(baseDummy); - for(MorphPart part : morphMap.get(MorphType.EYEBROW)){ - serialList.add(part); - } - for(MorphPart part : morphMap.get(MorphType.EYE)){ - serialList.add(part); - } - for(MorphPart part : morphMap.get(MorphType.LIP)){ - serialList.add(part); - } - for(MorphPart part : morphMap.get(MorphType.EXTRA)){ - serialList.add(part); - } - ListUtil.assignIndexedSerial(serialList); - - return; - } - - /** - * DOMからボーングループ情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildBoneGroupList(Element pmdModelElem) - throws TogaXmlException{ - Element boneGroupListElem = - getChild(pmdModelElem, "boneGroupList"); - - List boneGroupList = this.model.getBoneGroupList(); - BoneGroup defaultGroup = new BoneGroup(); - boneGroupList.add(defaultGroup); - - for(Element boneGroupElem - : eachChild(boneGroupListElem, "boneGroup")){ - BoneGroup group = new BoneGroup(); - boneGroupList.add(group); - - I18nText name = group.getGroupName(); - buildI18nName(boneGroupElem, name); - - for(Element boneGroupMemberElem - : eachChild(boneGroupElem, "boneGroupMember")){ - String boneIdRef = - getStringAttr(boneGroupMemberElem, "boneIdRef"); - BoneInfo bone = this.boneMap.get(boneIdRef); - group.getBoneList().add(bone); - } - } - - ListUtil.assignIndexedSerial(boneGroupList); - - return; - } - - /** - * DOMから剛体リスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildRigidList(Element pmdModelElem) - throws TogaXmlException{ - Element rigidListElem = - getChild(pmdModelElem, "rigidList"); - - List rigidList = this.model.getRigidList(); - - for(Element rigidElem : eachChild(rigidListElem, "rigid")){ - RigidInfo rigid = new RigidInfo(); - rigidList.add(rigid); - - I18nText name = rigid.getRigidName(); - buildI18nName(rigidElem, name); - - String behavior = getStringAttr(rigidElem, "behavior"); - RigidBehaviorType type = RigidBehaviorType.valueOf(behavior); - rigid.setBehaviorType(type); - - String rigidId = getStringAttr(rigidElem, "rigidId"); - this.rigidMap.put(rigidId, rigid); - - if(hasChild(rigidElem, "linkedBone")){ - Element linkedBoneElem = getChild(rigidElem, "linkedBone"); - String boneIdRef = getStringAttr(linkedBoneElem, "boneIdRef"); - BoneInfo linkedBone = this.boneMap.get(boneIdRef); - rigid.setLinkedBone(linkedBone); - } - - RigidShape rigidShape = rigid.getRigidShape(); - if(hasChild(rigidElem, "rigidShapeSphere")){ - Element shapeElem = - getChild(rigidElem, "rigidShapeSphere"); - float radius = getFloatAttr(shapeElem, "radius"); - rigidShape.setShapeType(RigidShapeType.SPHERE); - rigidShape.setRadius(radius); - } - if(hasChild(rigidElem, "rigidShapeBox")){ - Element shapeElem = - getChild(rigidElem, "rigidShapeBox"); - float width = getFloatAttr(shapeElem, "width"); - float height = getFloatAttr(shapeElem, "height"); - float depth = getFloatAttr(shapeElem, "depth"); - rigidShape.setShapeType(RigidShapeType.BOX); - rigidShape.setWidth(width); - rigidShape.setHeight(height); - rigidShape.setDepth(depth); - } - if(hasChild(rigidElem, "rigidShapeCapsule")){ - Element shapeElem = - getChild(rigidElem, "rigidShapeCapsule"); - float height = getFloatAttr(shapeElem, "height"); - float radius = getFloatAttr(shapeElem, "radius"); - rigidShape.setShapeType(RigidShapeType.CAPSULE); - rigidShape.setHeight(height); - rigidShape.setRadius(radius); - } - - float xVal; - float yVal; - float zVal; - - Element positionElem = getChild(rigidElem, "position"); - xVal = getFloatAttr(positionElem, "x"); - yVal = getFloatAttr(positionElem, "y"); - zVal = getFloatAttr(positionElem, "z"); - MkPos3D position = rigid.getPosition(); - position.setXpos(xVal); - position.setYpos(yVal); - position.setZpos(zVal); - - Element radRotationElem = getChild(rigidElem, "radRotation"); - xVal = getFloatAttr(radRotationElem, "xRad"); - yVal = getFloatAttr(radRotationElem, "yRad"); - zVal = getFloatAttr(radRotationElem, "zRad"); - Rad3d rotation = rigid.getRotation(); - rotation.setXRad(xVal); - rotation.setYRad(yVal); - rotation.setZRad(zVal); - - Element dynamicsElem = getChild(rigidElem, "dynamics"); - float mass = getFloatAttr(dynamicsElem, "mass"); - float dampingPosition = - getFloatAttr(dynamicsElem, "dampingPosition"); - float dampingRotation = - getFloatAttr(dynamicsElem, "dampingRotation"); - float restitution = getFloatAttr(dynamicsElem, "restitution"); - float friction = getFloatAttr(dynamicsElem, "friction"); - DynamicsInfo dynamics = rigid.getDynamicsInfo(); - dynamics.setMass(mass); - dynamics.setDampingPosition(dampingPosition); - dynamics.setDampingRotation(dampingRotation); - dynamics.setRestitution(restitution); - dynamics.setFriction(friction); - } - - ListUtil.assignIndexedSerial(rigidList); - - return; - } - - /** - * DOMから剛体グループリスト情報を組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildRigidGroupList(Element pmdModelElem) - throws TogaXmlException{ - Element rigidGroupListElem = - getChild(pmdModelElem, "rigidGroupList"); - - List groupList = this.model.getRigidGroupList(); - - for(Element rigidGroupElem - : eachChild(rigidGroupListElem, "rigidGroup")){ - RigidGroup rigidGroup = new RigidGroup(); - groupList.add(rigidGroup); - - String rigidGroupId = - getStringAttr(rigidGroupElem, "rigidGroupId"); - this.rigidGroupMap.put(rigidGroupId, rigidGroup); - - for(Element memberElem - : eachChild(rigidGroupElem, "rigidGroupMember")){ - String rigidIdRef = getStringAttr(memberElem, "rigidIdRef"); - RigidInfo rigid = this.rigidMap.get(rigidIdRef); - rigidGroup.getRigidList().add(rigid); - rigid.setRigidGroup(rigidGroup); - } - } - - while(groupList.size() < 16){ - RigidGroup rigidGroup = new RigidGroup(); - groupList.add(rigidGroup); - } - - ListUtil.assignIndexedSerial(groupList); - - return; - } - - /** - * DOM内の剛体衝突情報を解決する。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void resolveThroughRigidGroup(Element pmdModelElem) - throws TogaXmlException{ - Element rigidListElem = - getChild(pmdModelElem, "rigidList"); - - List rigidList = this.model.getRigidList(); - - Iterator rit = rigidList.iterator(); - for(Element rigidElem : eachChild(rigidListElem, "rigid")){ - RigidInfo rigid = rit.next(); - for(Element groupElem - : eachChild(rigidElem, "throughRigidGroup")){ - String groupId = getStringAttr(groupElem, "rigidGroupIdRef"); - RigidGroup group = this.rigidGroupMap.get(groupId); - rigid.getThroughGroupColl().add(group); - } - } - - return; - } - - /** - * DOMからジョイントリストを組み立てる。 - * @param pmdModelElem ルート要素 - * @throws TogaXmlException 構文エラー - */ - private void buildJointList(Element pmdModelElem) - throws TogaXmlException{ - Element jointListElem = - getChild(pmdModelElem, "jointList"); - - List jointList = this.model.getJointList(); - - for(Element jointElem : eachChild(jointListElem, "joint")){ - JointInfo joint = new JointInfo(); - jointList.add(joint); - - I18nText name = joint.getJointName(); - buildI18nName(jointElem, name); - - Element rigidPairElem = getChild(jointElem, "jointedRigidPair"); - String rigidIdRef1 = getStringAttr(rigidPairElem, "rigidIdRef1"); - String rigidIdRef2 = getStringAttr(rigidPairElem, "rigidIdRef2"); - RigidInfo rigid1 = this.rigidMap.get(rigidIdRef1); - RigidInfo rigid2 = this.rigidMap.get(rigidIdRef2); - joint.setRigidPair(rigid1, rigid2); - - float xVal; - float yVal; - float zVal; - float xFrom; - float xTo; - float yFrom; - float yTo; - float zFrom; - float zTo; - - MkPos3D position = joint.getPosition(); - Element positionElem = getChild(jointElem, "position"); - xVal = getFloatAttr(positionElem, "x"); - yVal = getFloatAttr(positionElem, "y"); - zVal = getFloatAttr(positionElem, "z"); - position.setXpos(xVal); - position.setYpos(yVal); - position.setZpos(zVal); - - TripletRange limitPosition = joint.getPositionRange(); - Element limitPositionElem = getChild(jointElem, "limitPosition"); - xFrom = getFloatAttr(limitPositionElem, "xFrom"); - xTo = getFloatAttr(limitPositionElem, "xTo"); - yFrom = getFloatAttr(limitPositionElem, "yFrom"); - yTo = getFloatAttr(limitPositionElem, "yTo"); - zFrom = getFloatAttr(limitPositionElem, "zFrom"); - zTo = getFloatAttr(limitPositionElem, "zTo"); - limitPosition.setXRange(xFrom, xTo); - limitPosition.setYRange(yFrom, yTo); - limitPosition.setZRange(zFrom, zTo); - - Rad3d rotation = joint.getRotation(); - Element rotationElem = getChild(jointElem, "radRotation"); - xVal = getFloatAttr(rotationElem, "xRad"); - yVal = getFloatAttr(rotationElem, "yRad"); - zVal = getFloatAttr(rotationElem, "zRad"); - rotation.setXRad(xVal); - rotation.setYRad(yVal); - rotation.setZRad(zVal); - - TripletRange limitRotation = joint.getRotationRange(); - Element limitRotationElem = getChild(jointElem, "limitRotation"); - xFrom = getFloatAttr(limitRotationElem, "xFrom"); - xTo = getFloatAttr(limitRotationElem, "xTo"); - yFrom = getFloatAttr(limitRotationElem, "yFrom"); - yTo = getFloatAttr(limitRotationElem, "yTo"); - zFrom = getFloatAttr(limitRotationElem, "zFrom"); - zTo = getFloatAttr(limitRotationElem, "zTo"); - limitRotation.setXRange(xFrom, xTo); - limitRotation.setYRange(yFrom, yTo); - limitRotation.setZRange(zFrom, zTo); - - MkPos3D elasticPosition = joint.getElasticPosition(); - Element elasticPositionElem = - getChild(jointElem, "elasticPosition"); - xVal = getFloatAttr(elasticPositionElem, "x"); - yVal = getFloatAttr(elasticPositionElem, "y"); - zVal = getFloatAttr(elasticPositionElem, "z"); - elasticPosition.setXpos(xVal); - elasticPosition.setYpos(yVal); - elasticPosition.setZpos(zVal); - - Deg3d elasticRotation = joint.getElasticRotation(); - Element elasticRotationElem = - getChild(jointElem, "elasticRotation"); - xVal = getFloatAttr(elasticRotationElem, "xDeg"); - yVal = getFloatAttr(elasticRotationElem, "yDeg"); - zVal = getFloatAttr(elasticRotationElem, "zDeg"); - elasticRotation.setXDeg(xVal); - elasticRotation.setYDeg(yVal); - elasticRotation.setZDeg(zVal); - } - - return; - } - -} diff --git a/src/main/java/jp/sfjp/mikutoga/pmd2xml/ModelFileType.java b/src/main/java/jp/sfjp/mikutoga/pmd2xml/ModelFileType.java index ae2c411..9375b97 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd2xml/ModelFileType.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd2xml/ModelFileType.java @@ -7,7 +7,7 @@ package jp.sfjp.mikutoga.pmd2xml; -import jp.sfjp.mikutoga.pmd.xml.XmlModelFileType; +import jp.sfjp.mikutoga.pmd.model.xml.XmlModelFileType; /** * モデルファイル種別。 diff --git a/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2Xml.java b/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2Xml.java index 06d432c..92f103a 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2Xml.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2Xml.java @@ -22,7 +22,7 @@ import java.text.MessageFormat; import java.util.Properties; import jp.sfjp.mikutoga.bin.parser.MmdFormatException; import jp.sfjp.mikutoga.pmd.IllegalPmdDataException; -import jp.sourceforge.mikutoga.xml.TogaXmlException; +import jp.sfjp.mikutoga.xml.TogaXmlException; import org.xml.sax.SAXException; /** diff --git a/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2XmlConv.java b/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2XmlConv.java index 07a24bb..f85f928 100644 --- a/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2XmlConv.java +++ b/src/main/java/jp/sfjp/mikutoga/pmd2xml/Pmd2XmlConv.java @@ -20,21 +20,22 @@ import javax.xml.parsers.ParserConfigurationException; import javax.xml.validation.Schema; import jp.sfjp.mikutoga.bin.parser.MmdFormatException; import jp.sfjp.mikutoga.pmd.IllegalPmdDataException; -import jp.sfjp.mikutoga.pmd.binio.PmdExporter; -import jp.sfjp.mikutoga.pmd.binio.PmdLoader; import jp.sfjp.mikutoga.pmd.model.PmdModel; -import jp.sfjp.mikutoga.pmd.xml.PmdXmlExporter; -import jp.sfjp.mikutoga.pmd.xml.Schema101009; -import jp.sfjp.mikutoga.pmd.xml.Schema130128; -import jp.sfjp.mikutoga.pmd.xml.XmlLoader; -import jp.sfjp.mikutoga.pmd.xml.XmlModelFileType; -import jp.sourceforge.mikutoga.xml.BotherHandler; -import jp.sourceforge.mikutoga.xml.LocalXmlResource; -import jp.sourceforge.mikutoga.xml.SchemaUtil; -import jp.sourceforge.mikutoga.xml.TogaXmlException; -import jp.sourceforge.mikutoga.xml.XmlResourceResolver; +import jp.sfjp.mikutoga.pmd.model.binio.PmdExporter; +import jp.sfjp.mikutoga.pmd.model.binio.PmdLoader; +import jp.sfjp.mikutoga.pmd.model.xml.PmdXmlExporter; +import jp.sfjp.mikutoga.pmd.model.xml.Schema101009; +import jp.sfjp.mikutoga.pmd.model.xml.Schema130128; +import jp.sfjp.mikutoga.pmd.model.xml.XmlModelFileType; +import jp.sfjp.mikutoga.pmd.model.xml.XmlPmdLoader; +import jp.sfjp.mikutoga.xml.BotherHandler; +import jp.sfjp.mikutoga.xml.LocalXmlResource; +import jp.sfjp.mikutoga.xml.SchemaUtil; +import jp.sfjp.mikutoga.xml.TogaXmlException; +import jp.sfjp.mikutoga.xml.XmlResourceResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; /** * PMD-XML間コンバータ本体。 @@ -320,9 +321,9 @@ public class Pmd2XmlConv { throws IOException, SAXException, TogaXmlException { - DocumentBuilder builder = buildBuilder(); - XmlLoader loader = new XmlLoader(); - PmdModel model = loader.parse(builder, source); + XMLReader reader = XmlInputUtil.buildReader(this.inTypes); + XmlPmdLoader loader = new XmlPmdLoader(reader); + PmdModel model = loader.parse(source); return model; } @@ -361,7 +362,7 @@ public class Pmd2XmlConv { writer = new OutputStreamWriter(ostream, CS_UTF8); writer = new BufferedWriter(writer); - exporter.putPmdModel(model, writer); + exporter.putPmdXml(model, writer); exporter.close(); diff --git a/src/main/java/jp/sfjp/mikutoga/pmd2xml/XmlInputUtil.java b/src/main/java/jp/sfjp/mikutoga/pmd2xml/XmlInputUtil.java new file mode 100644 index 0000000..0772100 --- /dev/null +++ b/src/main/java/jp/sfjp/mikutoga/pmd2xml/XmlInputUtil.java @@ -0,0 +1,146 @@ +/* + * xml input utility + * + * License : The MIT License + * Copyright(c) 2013 MikuToga Partners + */ + +package jp.sfjp.mikutoga.pmd2xml; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.validation.Schema; +import jp.sfjp.mikutoga.pmd.model.xml.Schema101009; +import jp.sfjp.mikutoga.pmd.model.xml.Schema130128; +import jp.sfjp.mikutoga.xml.BotherHandler; +import jp.sfjp.mikutoga.xml.LocalXmlResource; +import jp.sfjp.mikutoga.xml.SchemaUtil; +import jp.sfjp.mikutoga.xml.XmlResourceResolver; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * XML入力に関する各種ユーティリティ。 + */ +class XmlInputUtil { + + /** + * 隠しコンストラクタ。 + */ + private XmlInputUtil(){ + assert false; + throw new AssertionError(); + } + + + /** + * SAXパーサファクトリを生成する。 + *

    + *
  • XML名前空間機能は有効になる。 + *
  • DTDによる形式検証は無効となる。 + *
  • XIncludeによる差し込み機能は無効となる。 + *
+ * @param schema スキーマ + * @return ファクトリ + */ + private static SAXParserFactory buildFactory(Schema schema){ + SAXParserFactory factory = SAXParserFactory.newInstance(); + + factory.setNamespaceAware(true); + factory.setValidating(false); + factory.setXIncludeAware(false); +// factory.setFeature(name, value); + + factory.setSchema(schema); + + return factory; + } + + /** + * SAXパーサを生成する。 + * @param schema スキーマ + * @return SAXパーサ + */ + private static SAXParser buildParser(Schema schema){ + SAXParserFactory factory = buildFactory(schema); + + SAXParser parser; + try{ + parser = factory.newSAXParser(); + }catch(ParserConfigurationException e){ + assert false; + throw new AssertionError(e); + }catch(SAXException e){ + assert false; + throw new AssertionError(e); + } + +// parser.setProperty(name, value); + + return parser; + } + + /** + * スキーマを生成する。 + * @param resolver リゾルバ + * @param xmlInType 入力XML種別 + * @return スキーマ + */ + private static Schema builsSchema(XmlResourceResolver resolver, + ModelFileType xmlInType ){ + LocalXmlResource[] schemaArray; + switch(xmlInType){ + case XML_101009: + schemaArray = new LocalXmlResource[]{ + Schema101009.SINGLETON, + }; + break; + case XML_130128: + schemaArray = new LocalXmlResource[]{ + Schema130128.SINGLETON, + }; + break; + case XML_AUTO: + schemaArray = new LocalXmlResource[]{ + Schema101009.SINGLETON, + Schema130128.SINGLETON, + }; + break; + default: + throw new IllegalStateException(); + } + + Schema schema = SchemaUtil.newSchema(resolver, schemaArray); + + return schema; + } + + /** + * XMLリーダを生成する。 + *

エラーハンドラには{@link BotherHandler}が指定される。 + * @param xmlInType 入力XML種別 + * @return XMLリーダ + */ + static XMLReader buildReader(ModelFileType xmlInType){ + XmlResourceResolver resolver = new XmlResourceResolver(); + + Schema schema = builsSchema(resolver, xmlInType); + + SAXParser parser = buildParser(schema); + + XMLReader reader; + try{ + reader = parser.getXMLReader(); + }catch(SAXException e){ + assert false; + throw new AssertionError(e); + } + + reader.setEntityResolver(resolver); + reader.setErrorHandler(BotherHandler.HANDLER); + + return reader; + } + +} diff --git a/src/main/resources/jp/sfjp/mikutoga/pmd/xml/resources/pmdxml-101009.xsd b/src/main/resources/jp/sfjp/mikutoga/pmd/model/xml/resources/pmdxml-101009.xsd similarity index 100% rename from src/main/resources/jp/sfjp/mikutoga/pmd/xml/resources/pmdxml-101009.xsd rename to src/main/resources/jp/sfjp/mikutoga/pmd/model/xml/resources/pmdxml-101009.xsd diff --git a/src/main/resources/jp/sfjp/mikutoga/pmd/xml/resources/pmdxml-130128.xsd b/src/main/resources/jp/sfjp/mikutoga/pmd/model/xml/resources/pmdxml-130128.xsd similarity index 100% rename from src/main/resources/jp/sfjp/mikutoga/pmd/xml/resources/pmdxml-130128.xsd rename to src/main/resources/jp/sfjp/mikutoga/pmd/model/xml/resources/pmdxml-130128.xsd diff --git a/src/test/java/jp/sfjp/mikutoga/pmd2xml/ModelFileTypeTest.java b/src/test/java/jp/sfjp/mikutoga/pmd2xml/ModelFileTypeTest.java index 53a2dbb..8a20800 100644 --- a/src/test/java/jp/sfjp/mikutoga/pmd2xml/ModelFileTypeTest.java +++ b/src/test/java/jp/sfjp/mikutoga/pmd2xml/ModelFileTypeTest.java @@ -3,7 +3,7 @@ package jp.sfjp.mikutoga.pmd2xml; -import jp.sfjp.mikutoga.pmd.xml.XmlModelFileType; +import jp.sfjp.mikutoga.pmd.model.xml.XmlModelFileType; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; diff --git a/src/test/java/testdata/CnvAssert.java b/src/test/java/testdata/CnvAssert.java index 1d73e22..1932e57 100644 --- a/src/test/java/testdata/CnvAssert.java +++ b/src/test/java/testdata/CnvAssert.java @@ -57,6 +57,7 @@ public class CnvAssert { OutputStream destOut; destOut = new FileOutputStream(destFile); destOut = new BufferedOutputStream(destOut); +// destOut = new DebugOutputStream(destOut); Pmd2XmlConv converter = new Pmd2XmlConv(); converter.setInType(ModelFileType.XML_AUTO); @@ -188,12 +189,18 @@ public class CnvAssert { InputStream expis = new BufferedInputStream(expIn); InputStream resis = new BufferedInputStream(resIn); - + int offset = 0; for(;;){ int expCh = expis.read(); int resCh = resis.read(); - assertEquals(expCh, resCh); + try{ + assertEquals(expCh, resCh); + }catch(AssertionError e){ + System.err.println("offset=" + offset); + throw e; + } + offset++; if(expCh < 0) break; } diff --git a/src/test/java/testdata/DebugOutputStream.java b/src/test/java/testdata/DebugOutputStream.java new file mode 100644 index 0000000..535f6d6 --- /dev/null +++ b/src/test/java/testdata/DebugOutputStream.java @@ -0,0 +1,80 @@ +/* + */ + +package testdata; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * デバッガ監視用出力ストリーム。 + */ +public class DebugOutputStream extends OutputStream{ + + private final OutputStream os; + private long offset = 0L; + + + /** + * コンストラクタ。 + * @param os 委譲先出力ストリーム + */ + public DebugOutputStream(OutputStream os){ + super(); + this.os = os; + return; + } + + + /** + * デバッガ用監視場所。 + */ + private void before(){ + return; + } + + /** + * デバッガ用監視場所。 + */ + private void after(){ + this.offset++; + return; + } + + /** + * {@inheritDoc} + * @param b {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public void write(int b) throws IOException { + before(); + + this.os.write(b); + + after(); + + return; + } + + /** + * {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public void close() throws IOException { + this.os.close(); + return; + } + + /** + * {@inheritDoc} + * @throws IOException {@inheritDoc} + */ + @Override + public void flush() throws IOException { + this.os.flush(); + return; + } + +} diff --git a/src/test/resources/testdata/pmd101009/rigid/allrigid.xml b/src/test/resources/testdata/pmd101009/rigid/allrigid.xml index 9fa3b6e..32ba98a 100644 --- a/src/test/resources/testdata/pmd101009/rigid/allrigid.xml +++ b/src/test/resources/testdata/pmd101009/rigid/allrigid.xml @@ -135,7 +135,7 @@ Rigid behavior types: friction="0.5" /> - + diff --git a/src/test/resources/testdata/pmd130128/rigid/allrigid.xml b/src/test/resources/testdata/pmd130128/rigid/allrigid.xml index 1b150b3..7777827 100644 --- a/src/test/resources/testdata/pmd130128/rigid/allrigid.xml +++ b/src/test/resources/testdata/pmd130128/rigid/allrigid.xml @@ -135,7 +135,7 @@ Rigid behavior types: friction="0.5" /> - +