<dependency>
<groupId>jp.sourceforge.mikutoga</groupId>
<artifactId>togagem</artifactId>
- <version>2.102.5-SNAPSHOT</version>
+ <version>3.101.5-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
- <version>1.2</version>
+ <version>1.3.1</version>
<configuration>
<rules>
<requireMavenVersion>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
- <version>2.4</version>
+ <version>2.5.1</version>
</plugin>
<plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.14.1</version>
+ <version>2.16</version>
<configuration>
<skipTests>false</skipTests>
<enableAssertions>true</enableAssertions>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
- <version>2.10</version>
+ <version>2.11</version>
<!-- config from property value -->
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
- <version>2.9</version>
+ <version>2.9.1</version>
<configuration>
<skip>false</skip>
<notimestamp>true</notimestamp>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
- <version>2.14.1</version>
+ <version>2.16</version>
<configuration>
<showSuccess>false</showSuccess>
</configuration>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
- <version>2.10</version>
+ <version>2.11</version>
<configuration>
<skip>false</skip>
<!-- config from property value -->
<module name="RegexpSinglelineJava" />
-->
-<!-- バグ?
- <module name="RequireThis" />
--->
-
<!-- Obsolated
<module name="TabCharacter" />
-->
*/
public class RigidGroup implements SerialNumbered, Iterable<RigidInfo> {
+ public static final int MAX_RIGID_GROUP = 16;
+
+
private final List<RigidInfo> rigidList = new ArrayList<RigidInfo>();
private int serialNo = -1;
*/
public class ToonMap {
+ public static final int MAX_CUSTOM_TOON = 10;
private static final Map<Integer, String> DEF_TOONMAP;
static{
map.put(0xff, "toon0.bmp");
DEF_TOONMAP = Collections.unmodifiableMap(map);
+
+ assert DEF_TOONMAP.size() == MAX_CUSTOM_TOON + 1;
}
private final Map<Integer, String> 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;
}
/**
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;
}
/**
* 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;
* 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;
* 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;
* 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;
* Copyright(c) 2010 MikuToga Partners
*/
-package jp.sfjp.mikutoga.pmd.binio;
+package jp.sfjp.mikutoga.pmd.model.binio;
import java.io.OutputStream;
* 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;
* 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;
* 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;
* 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;
* 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;
* 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;
* 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;
* 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;
* 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;
* PMDモデルファイル(*.pmd)用入出力。
*/
-package jp.sfjp.mikutoga.pmd.binio;
+package jp.sfjp.mikutoga.pmd.model.binio;
/* EOF */
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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<BoneGroup> 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<IKChain> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<RigidGroup> 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<RigidGroup> 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<RigidInfo> 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<JointInfo> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<Material> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
+ for(MorphType type : MorphType.values()){
+ if(type == MorphType.BASE) continue;
+ List<MorphPart> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<Material> materialList = model.getMaterialList();
+ for(Material material : materialList){
+ List<Surface> 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<Surface> 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<Vertex> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<String, PmdTag> NAME_MAP =
+ new HashMap<String, PmdTag>();
+
+ 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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 =
+ "<?xml version=\"" + XML_VER
+ + "\" encoding=\"" + XML_ENC
+ + "\" ?>";
+
+ 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("<br/>").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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<IdRefHolder<Material>> materialSfcGroupIdRefList =
+ new LinkedList<IdRefHolder<Material>>();
+ private final List<IdRefHolder<Material>> materialToonIdRefList =
+ new LinkedList<IdRefHolder<Material>>();
+ private final Map<String, Integer> toonIdxMap =
+ new HashMap<String, Integer>();
+
+ // ボーン関連
+ private final Map<String, BoneInfo> boneIdMap =
+ new HashMap<String, BoneInfo>();
+ private final List<IdRefHolder<BoneInfo>> boneChainIdRefList =
+ new LinkedList<IdRefHolder<BoneInfo>>();
+ private final List<IdRefHolder<BoneInfo>> boneSourceIdRefList =
+ new LinkedList<IdRefHolder<BoneInfo>>();
+
+ // モーフ関連
+ private final List<IdRefHolder<MorphVertex>> morphVertexIdRefList =
+ new LinkedList<IdRefHolder<MorphVertex>>();
+
+ // 剛体関連
+ private final Map<String, RigidInfo> rigidIdMap =
+ new HashMap<String, RigidInfo>();
+ private final Map<String, RigidGroup> rigidGroupIdMap =
+ new HashMap<String, RigidGroup>();
+ private final List<IdRefHolder<RigidInfo>> thghRigidGroupIdRefList =
+ new LinkedList<IdRefHolder<RigidInfo>>();
+
+ // 面関連
+ private final Map<String, List<Surface>> surfaceGroupIdMap =
+ new HashMap<String, List<Surface>>();
+ private final List<IdRefHolder<Surface>> surfaceVertexIdRef =
+ new LinkedList<IdRefHolder<Surface>>();
+
+ // 頂点関連
+ private final Map<String, Vertex> vertexIdMap =
+ new HashMap<String, Vertex>();
+
+
+ /**
+ * コンストラクタ。
+ */
+ RefHelper(){
+ super();
+ return;
+ }
+
+
+ /**
+ * マテリアルからのサーフェイスグループID参照を登録する。
+ * @param material マテリアル
+ * @param idRef サーフェイスグループID参照
+ */
+ void addSurfaceGroupIdRef(Material material, String idRef){
+ IdRefHolder<Material> holder =
+ new IdRefHolder<Material>(material, idRef);
+ this.materialSfcGroupIdRefList.add(holder);
+
+ return;
+ }
+
+ /**
+ * サーフェイスグループの構成サーフェイスを登録する。
+ * @param surfaceGroupId サーフェイスグループID
+ * @param surface サーフェイス
+ */
+ void addSurfaceGroup(String surfaceGroupId, Surface surface){
+ List<Surface> surfaceGroup =
+ this.surfaceGroupIdMap.get(surfaceGroupId);
+ if(surfaceGroup == null){
+ surfaceGroup = new LinkedList<Surface>();
+ this.surfaceGroupIdMap.put(surfaceGroupId, surfaceGroup);
+ }
+
+ surfaceGroup.add(surface);
+
+ return;
+ }
+
+ /**
+ * マテリアルからのサーフェイスグループID参照を解決する。
+ */
+ void resolveMaterialSurfaceGroupId(){
+ for(IdRefHolder<Material> holder : this.materialSfcGroupIdRefList){
+ Material material = holder.getBody();
+ String surfaceGroupIdRef = holder.getIdRef();
+
+ List<Surface> surfaceGroup =
+ this.surfaceGroupIdMap.get(surfaceGroupIdRef);
+
+ List<Surface> surfaceList = material.getSurfaceList();
+ surfaceList.addAll(surfaceGroup);
+ }
+
+ return;
+ }
+
+ /**
+ * マテリアルからの共有トゥーンファイルID参照を追加登録する。
+ * @param material マテリアル
+ * @param idRef トゥーンファイルID参照
+ */
+ void addToonFileIdRef(Material material, String idRef){
+ IdRefHolder<Material> holder =
+ new IdRefHolder<Material>(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<Material> 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<BoneInfo> holder =
+ new IdRefHolder<BoneInfo>(bone, prevBoneIdRef, nextBoneIdRef);
+ this.boneChainIdRefList.add(holder);
+ return;
+ }
+
+ /**
+ * ボーン間チェーン参照情報を解決する。
+ */
+ void resolveBoneChainIdRef(){
+ for(IdRefHolder<BoneInfo> 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<BoneInfo> holder =
+ new IdRefHolder<BoneInfo>(bone, srcBoneIdRef);
+ this.boneSourceIdRefList.add(holder);
+ return;
+ }
+
+ /**
+ * ボーン情報からのソースボーンID参照を解決する。
+ */
+ void resolveSrcBoneIdRef(){
+ for(IdRefHolder<BoneInfo> 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<MorphVertex> holder =
+ new IdRefHolder<MorphVertex>(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<RigidInfo> holder =
+ new IdRefHolder<RigidInfo>(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<RigidInfo> holder : this.thghRigidGroupIdRefList){
+ RigidInfo rigid = holder.getBody();
+ String rigidGroupIdRef = holder.getIdRef();
+ RigidGroup group = this.rigidGroupIdMap.get(rigidGroupIdRef);
+
+ Collection<RigidGroup> 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<Surface> holder =
+ new IdRefHolder<Surface>(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<MorphVertex> 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<Surface> 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 <E> ID参照元インスタンス型
+ */
+ private static final class IdRefHolder<E> {
+
+ 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;
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * 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<BoneInfo> 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<BoneInfo> 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<BoneGroup> boneGroupList =
+ this.getPmdModel().getBoneGroupList();
+ boneGroupList.add(defaultBoneGroup);
+
+ return;
+ }
+
+ /**
+ * boneGroupListタグ終了の通知を受け取る。
+ */
+ @CloseXmlMark(PmdTag.BONE_GROUP_LIST)
+ void closeBoneGroupList(){
+ List<BoneGroup> 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<BoneGroup> 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<BoneInfo> 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<IKChain> 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<BoneInfo> chainList = this.currentIkChain.getChainedBoneList();
+ chainList.add(bone);
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * 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<RigidInfo> 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<RigidInfo> 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<RigidGroup> 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<RigidInfo> memberList = this.currentRigidGroup.getRigidList();
+ memberList.add(member);
+ member.setRigidGroup(this.currentRigidGroup);
+
+ return;
+ }
+
+ /**
+ * rigidGroupListタグ終了の通知を受け取る。
+ * 剛体グループ総数が定員に満たない場合は自動追加される。
+ */
+ @CloseXmlMark(PmdTag.RIGID_GROUP_LIST)
+ void closeRigidGroupList(){
+
+ this.helper.resolveThroughRigidGroupIdRef();
+
+ List<RigidGroup> 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<JointInfo> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<PmdTag, Method> openDispatcher;
+ private final Map<PmdTag, Method> 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<Method> filtMethod(Class<?> klass,
+ Class<? extends Annotation> filter ){
+ Collection<Method> result = new LinkedList<Method>();
+
+ 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<PmdTag, Method> getOpenDispatcher(Class<?> klass){
+ Map<PmdTag, Method> result =
+ new EnumMap<PmdTag, Method>(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<PmdTag, Method> getCloseDispatcher(Class<?> klass){
+ Map<PmdTag, Method> result =
+ new EnumMap<PmdTag, Method>(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<PmdTag, Method> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<Material> 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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<MorphType, List<MorphPart>> morphMap =
+ getPmdModel().getMorphMap();
+ List<MorphPart> tempList = new LinkedList<MorphPart>();
+
+ 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<MorphType, List<MorphPart>> morphMap =
+ getPmdModel().getMorphMap();
+
+ MorphType morphType = this.currentMorph.getMorphType();
+ List<MorphPart> 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<MorphVertex> morphVertexList =
+ this.currentMorph.getMorphVertexList();
+ morphVertexList.add(morphVertex);
+
+ return;
+ }
+
+}
--- /dev/null
+/*
+ * 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<Surface> 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<Vertex> 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<Vertex> vertexList = getPmdModel().getVertexList();
+ ListUtil.assignIndexedSerial(vertexList);
+
+ return;
+ }
+
+}
* 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各種リソースの定義。
* 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各種リソースの定義。
--- /dev/null
+/*
+ * 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ハンドラ。
+ * <p>下位リスナに各種通知が振り分けられる。
+ */
+class XmlHandler implements ContentHandler{
+
+ private final Map<PmdTag, SaxListener> 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, SaxListener>(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;
+ }
+
+}
* Copyright(c) 2013 MikuToga Partners
*/
-package jp.sfjp.mikutoga.pmd.xml;
+package jp.sfjp.mikutoga.pmd.model.xml;
/**
* XMLファイルスキーマ種別。
--- /dev/null
+/*
+ * 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;
+
+
+ /**
+ * コンストラクタ。
+ * <p>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();
+ }
+
+}
*/
/**
- * PMDモデル内容をXMLで出力するためのライブラリ。
+ * PMDã\83¢ã\83\87ã\83«å\86\85容ã\82\92XMLã\81§å\85¥å\87ºå\8a\9bã\81\99ã\82\8bã\81\9fã\82\81ã\81®ã\83©ã\82¤ã\83\96ã\83©ã\83ªã\80\82
*/
-package jp.sfjp.mikutoga.pmd.xml;
+package jp.sfjp.mikutoga.pmd.model.xml;
/* EOF */
+++ /dev/null
-/*
- * 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("<i18nName ");
- putAttr("lang", lang639).sp();
- putAttr("name", name);
- 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("<position ");
- putFloatAttr("x", (float) position.getXpos()).sp();
- putFloatAttr("y", (float) position.getYpos()).sp();
- putFloatAttr("z", (float) position.getZpos()).sp();
- putRawText("/>");
- return this;
- }
-
- /**
- * 姿勢情報(ラジアン)を出力する。
- * @param rotation 姿勢情報
- * @return this本体
- * @throws IOException 出力エラー
- */
- protected PmdXmlExporter putRadRotation(Rad3d rotation)
- throws IOException{
- putRawText("<radRotation ");
- putFloatAttr("xRad", rotation.getXRad()).sp();
- putFloatAttr("yRad", rotation.getYRad()).sp();
- putFloatAttr("zRad", rotation.getZRad()).sp();
- 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("<?xml")
- .sp().putAttr("version","1.0")
- .sp().putAttr("encoding","UTF-8")
- .sp().putRawText("?>").ln(2);
-
- ind().putBlockComment(TOP_COMMENT).ln(2);
-
- I18nText modelName = model.getModelName();
- ind().putLocalNameComment(modelName).ln();
- ind().putRawText("<pmdModel").ln();
- pushNest();
-
- String defns;
- String xsduri;
- String version;
- if(this.xmlType == XmlModelFileType.XML_101009){
- defns = Schema101009.NS_PMDXML;
- xsduri = Schema101009.SCHEMA_PMDXML;
- version = Schema101009.VER_PMDXML;
- }else if(this.xmlType == XmlModelFileType.XML_130128){
- defns = Schema130128.NS_PMDXML;
- xsduri = Schema130128.SCHEMA_PMDXML;
- version = Schema130128.VER_PMDXML;
- }else{
- assert false;
- throw new AssertionError();
- }
-
- ind().putAttr("xmlns", defns).ln();
-
- ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
-
- ind().putRawText("xsi:schemaLocation").putRawText("=\"");
- putRawText(defns).ln();
- pushNest();
- ind().putRawText(xsduri).putRawCh('"').ln();
- popNest();
-
- ind().putAttr("schemaVersion", version).ln(2);
- ind().putPrimaryNameAttr("name", modelName).ln();
-
- popNest();
- 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("</pmdModel>").ln(2);
- ind().putRawText("<!-- EOF -->").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("<description");
- if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
- sp().putAttr("lang", lang639).sp();
- }
- putRawText(">").ln();
-
- putBRedContent(text);
-
- ind().putRawText("</description>").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("<br/>").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("<license>").ln();
- ind().putRawText("</license>").ln(2);
-
- ind().putRawText("<credits>").ln();
- ind().putRawText("</credits>").ln(2);
-
- if(this.generator != null){
- ind().putRawText("<meta ");
- putAttr("name", "generator").sp()
- .putAttr("content", this.generator);
- putRawText(" />").ln();
- }
-
- ind().putRawText("<meta ");
- putAttr("name", "siteURL").sp().putAttr("content", "");
- putRawText(" />").ln();
- ind().putRawText("<meta ");
- putAttr("name", "imageURL").sp().putAttr("content", "");
- putRawText(" />").ln(2);
-
- return this;
- }
-
- /**
- * マテリアル素材一覧を出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putMaterialList(PmdModel model)
- throws IOException{
- ind().putRawText("<materialList>").ln();
-
- pushNest();
- int ct = 0;
- boolean dumped = false;
- List<Material> materialList = model.getMaterialList();
- for(Material material : materialList){
- if( ! dumped ) ln();
- putMaterial(material, ct++);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</materialList>").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("<material ");
- if(primary != null && primary.length() > 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("<diffuse ");
- putFloatAttr("r", rgba[0]).sp();
- putFloatAttr("g", rgba[1]).sp();
- putFloatAttr("b", rgba[2]).sp();
- putFloatAttr("alpha", rgba[3]).sp();
- putRawText("/>").ln();
-
- Color specular = material.getSpecularColor();
- specular.getRGBComponents(rgba);
- float shininess = material.getShininess();
- ind().putRawText("<specular ");
- putFloatAttr("r", rgba[0]).sp();
- putFloatAttr("g", rgba[1]).sp();
- putFloatAttr("b", rgba[2]).sp();
- putFloatAttr("shininess", shininess).sp();
- putRawText("/>").ln();
-
- Color ambient = material.getAmbientColor();
- ambient.getRGBComponents(rgba);
- ind().putRawText("<ambient ");
- putFloatAttr("r", rgba[0]).sp();
- putFloatAttr("g", rgba[1]).sp();
- putFloatAttr("b", rgba[2]).sp();
- putRawText("/>").ln();
-
- ShadeInfo shade = material.getShadeInfo();
- String textureFileName = shade.getTextureFileName();
- String spheremapFileName = shade.getSpheremapFileName();
-
- if(shade.isValidToonIndex()){
- ind().putRawText("<toon ");
- int toonIdx = shade.getToonIndex();
- putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
- putRawText(" />");
- String toonFileName = shade.getToonFileName();
- if(toonFileName != null && toonFileName.length() > 0){
- sp().putLineComment(toonFileName);
- }
- ln();
- }
-
- if(textureFileName != null && textureFileName.length() > 0){
- ind().putRawText("<textureFile ");
- putAttr("winFileName", textureFileName);
- putRawText(" />").ln();
- }
-
- if(spheremapFileName != null && spheremapFileName.length() > 0){
- ind().putRawText("<spheremapFile ");
- putAttr("winFileName", spheremapFileName);
- putRawText(" />").ln();
- }
-
- popNest();
- ind().putRawText("</material>").ln(2);
-
- return this;
- }
-
- /**
- * トゥーンファイルマッピング情報を出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putToonMap(PmdModel model)
- throws IOException{
- ind().putRawText("<toonMap>").ln();
- pushNest();
-
- ToonMap map = model.getToonMap();
- for(int index = 0; index <= 9; index++){
- ind().putToon(map, index).ln();
- }
-
- popNest();
- ind().putRawText("</toonMap>").ln(2);
- return this;
- }
-
- /**
- * 個別のトゥーンファイル情報を出力する。
- * @param map トゥーンマップ
- * @param index インデックス値
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putToon(ToonMap map, int index)
- throws IOException{
- putRawText("<toonDef ");
- putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).sp();
- putIntAttr("index", index).sp();
- String toonFile = map.getIndexedToon(index);
- putAttr("winFileName", toonFile);
- putRawText(" />");
- putUnescapedComment(toonFile);
- return this;
- }
-
- /**
- * サーフェイスグループリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putSurfaceGroupList(PmdModel model)
- throws IOException{
- ind().putRawText("<surfaceGroupList>").ln();
-
- pushNest();
- int ct = 0;
- boolean dumped = false;
- List<Material> materialList = model.getMaterialList();
- for(Material material : materialList){
- List<Surface> surfaceList = material.getSurfaceList();
- if( ! dumped ) ln();
- putSurfaceList(surfaceList, ct++);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</surfaceGroupList>").ln(2);
-
- return this;
- }
-
- /**
- * 個別のサーフェイスグループを出力する。
- * @param surfaceList サーフェイスのリスト
- * @param index グループインデックス
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putSurfaceList(List<Surface> surfaceList,
- int index)
- throws IOException{
- ind().putRawText("<surfaceGroup ");
- putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
- sp().putRawText(">").ln();
- pushNest();
-
- for(Surface surface : surfaceList){
- putSurface(surface);
- }
-
- popNest();
- ind().putRawText("</surfaceGroup>").ln(2);
-
- return this;
- }
-
- /**
- * 個別のサーフェイスを出力する。
- * @param surface サーフェイス
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putSurface(Surface surface)
- throws IOException{
- ind().putRawText("<surface ");
-
- Vertex vertex1 = surface.getVertex1();
- Vertex vertex2 = surface.getVertex2();
- Vertex vertex3 = surface.getVertex3();
-
- putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).sp();
- putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).sp();
- putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).sp();
-
- putRawText("/>").ln();
- return this;
- }
-
- /**
- * 頂点リストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putVertexList(PmdModel model)
- throws IOException{
- ind().putRawText("<vertexList>").ln();
-
- pushNest();
- boolean dumped = false;
- List<Vertex> vertexList = model.getVertexList();
- for(Vertex vertex : vertexList){
- if( ! dumped ) ln();
- putVertex(vertex);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</vertexList>").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("<vertex ");
- putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).sp();
- putAttr("showEdge", bool);
- sp().putRawText(">").ln();
- pushNest();
-
- MkPos3D position = vertex.getPosition();
- ind().putPosition(position).ln();
-
- MkVec3D normal = vertex.getNormal();
- ind().putRawText("<normal ");
- putFloatAttr("x", (float) normal.getXVal()).sp();
- putFloatAttr("y", (float) normal.getYVal()).sp();
- putFloatAttr("z", (float) normal.getZVal()).sp();
- putRawText("/>").ln();
-
- MkPos2D uvPos = vertex.getUVPosition();
- ind().putRawText("<uvMap ");
- putFloatAttr("u", (float) uvPos.getXpos()).sp();
- putFloatAttr("v", (float) uvPos.getYpos()).sp();
- putRawText("/>").ln();
-
- BoneInfo boneA = vertex.getBoneA();
- BoneInfo boneB = vertex.getBoneB();
- int weight = vertex.getWeightA();
- ind().putRawText("<skinning ");
- putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).sp();
- putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).sp();
- putIntAttr("weightBalance", weight).sp();
- putRawText("/>").ln();
-
- popNest();
- ind().putRawText("</vertex>").ln(2);
-
- return this;
- }
-
- /**
- * ボーンリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putBoneList(PmdModel model)
- throws IOException{
- ind().putRawText("<boneList>").ln();
- pushNest();
-
- boolean dumped = false;
- for(BoneInfo bone : model.getBoneList()){
- if( ! dumped ){
- ln().putBlockComment(BONETYPE_COMMENT).ln();
- }
- putBone(bone);
- dumped = true;
- }
-
- popNest();
- ind().putRawText("</boneList>").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("<bone ");
- putPrimaryNameAttr("name", i18nName).sp();
- putNumberedIdAttr("boneId", PFX_BONE, bone).sp();
- putAttr("type", type.name());
- sp().putRawText(">").ln();
- pushNest();
-
- putI18nName(i18nName);
-
- MkPos3D position = bone.getPosition();
- ind().putPosition(position).ln();
-
- BoneInfo srcBone = bone.getSrcBone();
- if(bone.getBoneType() == BoneType.LINKEDROT){
- ind().putRawText("<rotationRatio ");
- putIntAttr("ratio", bone.getRotationRatio());
- putRawText(" />").ln();
- }else if(srcBone != null){
- String iktag;
- switch(getXmlFileType()){
- case XML_101009:
- iktag = "<ikBone ";
- break;
- case XML_130128:
- iktag = "<sourceBone ";
- break;
- default:
- assert false;
- throw new AssertionError();
- }
- ind().putRawText(iktag);
- putNumberedIdAttr("boneIdRef", PFX_BONE, srcBone);
- putRawText(" /> ");
- 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("<boneChain");
- if(prev != null){
- sp();
- putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
- }
- if(next != null){
- sp();
- putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
- }
- putRawText(" />").ln();
-
- popNest();
- ind().putRawText("</bone>").ln(2);
-
- return this;
- }
-
- /**
- * ボーングループリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putBoneGroupList(PmdModel model)
- throws IOException{
- ind().putRawText("<boneGroupList>").ln();
-
- pushNest();
- boolean dumped = false;
- List<BoneGroup> groupList = model.getBoneGroupList();
- for(BoneGroup group : groupList){
- if(group.isDefaultBoneGroup()) continue;
- if( ! dumped ) ln();
- putBoneGroup(group);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</boneGroupList>").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("<boneGroup ");
- putPrimaryNameAttr("name", i18nName);
- sp().putRawText(">").ln();
- pushNest();
-
- putI18nName(i18nName);
-
- for(BoneInfo bone : group){
- ind().putRawText("<boneGroupMember ");
- putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
- putRawText(" /> ");
- String boneName = "Ref:" + bone.getBoneName().getText();
- putLineComment(boneName).ln();
- }
-
- popNest();
- ind().putRawText("</boneGroup>").ln(2);
-
- return this;
- }
-
- /**
- * IKチェーンリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putIKChainList(PmdModel model)
- throws IOException{
- ind().putRawText("<ikChainList>").ln();
-
- pushNest();
- boolean dumped = false;
- List<IKChain> chainList = model.getIKChainList();
- for(IKChain chain : chainList){
- if( ! dumped ) ln();
- putIKChain(chain);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</ikChainList>").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("<ikChain ");
- putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).sp();
- putIntAttr("recursiveDepth", depth).sp();
- putFloatAttr("weight", weight);
- sp().putRawText(">").ln();
- pushNest();
-
- for(BoneInfo bone : chain){
- ind().putRawText("<chainOrder ");
- putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
- putRawText(" /> ");
- putLineComment("Ref:" + bone.getBoneName().getText());
- ln();
- }
-
- popNest();
- ind().putRawText("</ikChain>").ln(2);
-
- return this;
- }
-
- /**
- * モーフリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putMorphList(PmdModel model)
- throws IOException{
- ind().putRawText("<morphList>").ln();
- pushNest();
-
- boolean dumped = false;
- Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
- for(MorphType type : MorphType.values()){
- if(type == MorphType.BASE) continue;
- List<MorphPart> 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("</morphList>").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("<morph ");
- putAttr("name", primary).sp();
- putAttr("type", part.getMorphType().name());
- sp().putRawText(">");
- ln();
- pushNest();
-
- putI18nName(i18nName);
-
- for(MorphVertex mvertex : part){
- MkPos3D offset = mvertex.getOffset();
- Vertex base = mvertex.getBaseVertex();
-
- ind().putRawText("<morphVertex ");
- putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).sp();
- putFloatAttr("xOff", (float) offset.getXpos()).sp();
- putFloatAttr("yOff", (float) offset.getYpos()).sp();
- putFloatAttr("zOff", (float) offset.getZpos()).sp();
- putRawText("/>");
- ln();
- }
-
- popNest();
- ind().putRawText("</morph>").ln(2);
-
- return this;
- }
-
- /**
- * 剛体リストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putRigidList(PmdModel model)
- throws IOException{
- ind().putRawText("<rigidList>").ln();
- pushNest();
-
- boolean dumped = false;
- for(RigidInfo rigid : model.getRigidList()){
- if( ! dumped ){
- ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
- }
- putRigid(rigid);
- dumped = true;
- }
-
- popNest();
- ind().putRawText("</rigidList>").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("<rigid ");
- putAttr("name", primary).sp();
- putNumberedIdAttr("rigidId", PFX_RIGID, rigid).sp();
- putAttr("behavior", rigid.getBehaviorType().name());
- sp().putRawText(">").ln();
- pushNest();
-
- putI18nName(i18nName);
-
- if(linkedBone != null){
- ind().putRawText("<linkedBone ");
- putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
- 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("<throughRigidGroup ");
- putNumberedIdAttr("rigidGroupIdRef",
- PFX_RIGIDGROUP,
- group.getSerialNumber() + 1).sp();
- putRawText(" />").ln();
- }
-
- popNest();
- ind().putRawText("</rigid>").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("<rigidShapeBox ");
- putFloatAttr("width", shape.getWidth()).sp();
- putFloatAttr("height", shape.getHeight()).sp();
- putFloatAttr("depth", shape.getDepth()).sp();
- break;
- case SPHERE:
- ind().putRawText("<rigidShapeSphere ");
- putFloatAttr("radius", shape.getRadius()).sp();
- break;
- case CAPSULE:
- ind().putRawText("<rigidShapeCapsule ");
- putFloatAttr("height", shape.getHeight()).sp();
- putFloatAttr("radius", shape.getRadius()).sp();
- break;
- default:
- assert false;
- throw new AssertionError();
- }
-
- putRawText("/>").ln();
-
- return this;
- }
-
- /**
- * 力学設定を出力する。
- * @param dynamics 力学設定
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putDynamics(DynamicsInfo dynamics)
- throws IOException{
- ind().putRawText("<dynamics").ln();
- pushNest();
- ind().putFloatAttr("mass", dynamics.getMass()).ln();
- ind().putFloatAttr("dampingPosition",
- dynamics.getDampingPosition()).ln();
- ind().putFloatAttr("dampingRotation",
- dynamics.getDampingRotation()).ln();
- ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
- ind().putFloatAttr("friction", dynamics.getFriction()).ln();
- popNest();
- ind().putRawText("/>").ln();
-
- return this;
- }
-
- /**
- * 剛体グループリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putRigidGroupList(PmdModel model)
- throws IOException{
- ind().putRawText("<rigidGroupList>").ln(2);
- pushNest();
-
- boolean singleLast = false;
- for(RigidGroup group : model.getRigidGroupList()){
- List<RigidInfo> rigidList = group.getRigidList();
- if(singleLast && ! rigidList.isEmpty()){
- ln();
- }
- ind().putRawText("<rigidGroup ");
- putNumberedIdAttr("rigidGroupId",
- PFX_RIGIDGROUP,
- group.getSerialNumber() + 1);
- if(rigidList.isEmpty()){
- putRawText(" />").ln();
- singleLast = true;
- continue;
- }
- putRawText(" >").ln();
- pushNest();
-
- for(RigidInfo rigid : rigidList){
- ind().putRawText("<rigidGroupMember ");
- putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).sp();
- putRawText("/>");
- sp();
- putLineComment("Ref:" + rigid.getRigidName().getText());
- ln();
- }
-
- popNest();
- ind().putRawText("</rigidGroup>").ln(2);
- singleLast = false;
- }
-
- if(singleLast){
- ln();
- }
-
- popNest();
- ind().putRawText("</rigidGroupList>").ln(2);
-
- return this;
- }
-
- /**
- * ジョイントリストを出力する。
- * @param model モデルデータ
- * @return this本体
- * @throws IOException 出力エラー
- */
- private PmdXmlExporter putJointList(PmdModel model)
- throws IOException{
- ind().putRawText("<jointList>").ln();
-
- pushNest();
- boolean dumped = false;
- List<JointInfo> jointList = model.getJointList();
- for(JointInfo joint : jointList){
- if( ! dumped ) ln();
- putJoint(joint);
- dumped = true;
- }
- popNest();
-
- ind().putRawText("</jointList>").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("<joint ");
- putPrimaryNameAttr("name", i18nName);
- sp().putRawText(">").ln();
- pushNest();
-
- putI18nName(i18nName);
-
- RigidInfo rigidA = joint.getRigidA();
- RigidInfo rigidB = joint.getRigidB();
-
- ind();
- putLineComment("[" + rigidA.getRigidName().getText() + "]"
- + " <=> [" + rigidB.getRigidName().getText() + "]");
- ln();
-
- ind().putRawText("<jointedRigidPair ");
- putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).sp();
- putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).sp();
- putRawText("/>").ln(2);
-
- MkPos3D position = joint.getPosition();
- ind().putPosition(position).ln();
-
- TripletRange posRange = joint.getPositionRange();
- ind().putRawText("<limitPosition").ln();
- pushNest();
- ind();
- putFloatAttr("xFrom", posRange.getXFrom()).sp();
- putFloatAttr("xTo", posRange.getXTo()).ln();
- ind();
- putFloatAttr("yFrom", posRange.getYFrom()).sp();
- putFloatAttr("yTo", posRange.getYTo()).ln();
- ind();
- putFloatAttr("zFrom", posRange.getZFrom()).sp();
- putFloatAttr("zTo", posRange.getZTo()).ln();
- popNest();
- ind().putRawText("/>").ln(2);
-
- Rad3d rotation = joint.getRotation();
- ind().putRadRotation(rotation).ln();
- TripletRange rotRange = joint.getRotationRange();
- ind().putRawText("<limitRotation").ln();
- pushNest();
- ind();
- putFloatAttr("xFrom", rotRange.getXFrom()).sp();
- putFloatAttr("xTo", rotRange.getXTo()).ln();
- ind();
- putFloatAttr("yFrom", rotRange.getYFrom()).sp();
- putFloatAttr("yTo", rotRange.getYTo()).ln();
- ind();
- putFloatAttr("zFrom", rotRange.getZFrom()).sp();
- putFloatAttr("zTo", rotRange.getZTo()).ln();
- popNest();
- ind().putRawText("/>").ln(2);
-
- MkPos3D elaPosition = joint.getElasticPosition();
- ind().putRawText("<elasticPosition ");
- putFloatAttr("x", (float) elaPosition.getXpos()).sp();
- putFloatAttr("y", (float) elaPosition.getYpos()).sp();
- putFloatAttr("z", (float) elaPosition.getZpos()).sp();
- putRawText("/>").ln();
-
- Deg3d elaRotation = joint.getElasticRotation();
- ind().putRawText("<elasticRotation ");
- putFloatAttr("xDeg", elaRotation.getXDeg()).sp();
- putFloatAttr("yDeg", elaRotation.getYDeg()).sp();
- putFloatAttr("zDeg", elaRotation.getZDeg()).sp();
- putRawText("/>").ln(2);
-
- popNest();
- ind().putRawText("</joint>").ln(2);
-
- return this;
- }
-
-}
+++ /dev/null
-/*
- * 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<String, Integer> toonIdxMap =
- new HashMap<String, Integer>();
- private final Map<String, BoneInfo> boneMap =
- new HashMap<String, BoneInfo>();
- private final Map<String, Vertex> vertexMap =
- new HashMap<String, Vertex>();
- private final Map<String, List<Surface>> surfaceGroupMap =
- new HashMap<String, List<Surface>>();
- private final Map<String, RigidInfo> rigidMap =
- new HashMap<String, RigidInfo>();
- private final Map<String, RigidGroup> rigidGroupMap =
- new HashMap<String, RigidGroup>();
-
- 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<Element> 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<BoneInfo> 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<BoneInfo> 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<Vertex> 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<Surface> surfaceList = buildSurface(surfaceGroupElem);
-
- this.surfaceGroupMap.put(groupId, surfaceList);
- }
-
- return;
- }
-
- /**
- * DOMからポリゴン情報を組み立てる。
- * @param surfaceGroupElem surfaceGroup要素
- * @return ポリゴンリスト
- * @throws TogaXmlException 構文エラー
- */
- private List<Surface> buildSurface(Element surfaceGroupElem)
- throws TogaXmlException{
- List<Surface> result = new ArrayList<Surface>();
-
- 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<Surface> surfaceList = this.model.getSurfaceList();
- List<Material> 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<Surface> 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<IKChain> 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<BoneInfo> 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<MorphType, List<MorphPart>> 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<MorphVertex> 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<MorphPart> serialList = new LinkedList<MorphPart>();
- 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<BoneGroup> 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<RigidInfo> 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<RigidGroup> 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<RigidInfo> rigidList = this.model.getRigidList();
-
- Iterator<RigidInfo> 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<JointInfo> 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;
- }
-
-}
package jp.sfjp.mikutoga.pmd2xml;
-import jp.sfjp.mikutoga.pmd.xml.XmlModelFileType;
+import jp.sfjp.mikutoga.pmd.model.xml.XmlModelFileType;
/**
* モデルファイル種別。
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;
/**
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間コンバータ本体。
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;
}
writer = new OutputStreamWriter(ostream, CS_UTF8);
writer = new BufferedWriter(writer);
- exporter.putPmdModel(model, writer);
+ exporter.putPmdXml(model, writer);
exporter.close();
--- /dev/null
+/*
+ * 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パーサファクトリを生成する。
+ * <ul>
+ * <li>XML名前空間機能は有効になる。
+ * <li>DTDによる形式検証は無効となる。
+ * <li>XIncludeによる差し込み機能は無効となる。
+ * </ul>
+ * @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リーダを生成する。
+ * <p>エラーハンドラには{@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;
+ }
+
+}
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;
OutputStream destOut;
destOut = new FileOutputStream(destFile);
destOut = new BufferedOutputStream(destOut);
+// destOut = new DebugOutputStream(destOut);
Pmd2XmlConv converter = new Pmd2XmlConv();
converter.setInType(ModelFileType.XML_AUTO);
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;
}
--- /dev/null
+/*
+ */
+
+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;
+ }
+
+}
friction="0.5"
/>
- <throughRigidGroup rigidGroupIdRef="rg1" />
+ <throughRigidGroup rigidGroupIdRef="rg1" />
</rigid>
</rigidList>
friction="0.5"
/>
- <throughRigidGroup rigidGroupIdRef="rg1" />
+ <throughRigidGroup rigidGroupIdRef="rg1" />
</rigid>
</rigidList>