4 * License : The MIT License
5 * Copyright(c) 2010 MikuToga Partners
8 package jp.sfjp.mikutoga.pmd.xml;
10 import java.awt.Color;
11 import java.io.IOException;
12 import java.io.OutputStream;
13 import java.util.List;
15 import jp.sfjp.mikutoga.pmd.model.BoneGroup;
16 import jp.sfjp.mikutoga.pmd.model.BoneInfo;
17 import jp.sfjp.mikutoga.pmd.model.DynamicsInfo;
18 import jp.sfjp.mikutoga.pmd.model.IKChain;
19 import jp.sfjp.mikutoga.pmd.model.JointInfo;
20 import jp.sfjp.mikutoga.pmd.model.Material;
21 import jp.sfjp.mikutoga.pmd.model.MorphPart;
22 import jp.sfjp.mikutoga.pmd.model.MorphVertex;
23 import jp.sfjp.mikutoga.pmd.model.PmdModel;
24 import jp.sfjp.mikutoga.pmd.model.RigidGroup;
25 import jp.sfjp.mikutoga.pmd.model.RigidInfo;
26 import jp.sfjp.mikutoga.pmd.model.RigidShape;
27 import jp.sfjp.mikutoga.pmd.model.SerialNumbered;
28 import jp.sfjp.mikutoga.pmd.model.ShadeInfo;
29 import jp.sfjp.mikutoga.pmd.model.Surface;
30 import jp.sfjp.mikutoga.pmd.model.ToonMap;
31 import jp.sfjp.mikutoga.pmd.model.Vertex;
32 import jp.sourceforge.mikutoga.corelib.I18nText;
33 import jp.sourceforge.mikutoga.math.MkPos2D;
34 import jp.sourceforge.mikutoga.math.MkPos3D;
35 import jp.sourceforge.mikutoga.math.MkVec3D;
36 import jp.sourceforge.mikutoga.pmd.BoneType;
37 import jp.sourceforge.mikutoga.pmd.Deg3d;
38 import jp.sourceforge.mikutoga.pmd.MorphType;
39 import jp.sourceforge.mikutoga.pmd.Rad3d;
40 import jp.sourceforge.mikutoga.pmd.RigidShapeType;
41 import jp.sourceforge.mikutoga.pmd.TripletRange;
42 import jp.sourceforge.mikutoga.xml.BasicXmlExporter;
43 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
46 * 101009形式XMLでPMDモデルデータを出力する。
48 public class XmlExporter extends BasicXmlExporter{
50 private static final String TOP_COMMENT =
52 + " model-data(*.pmd) on XML";
55 private static final String CR = "\r"; // 0x0d
57 private static final String LF = "\n"; // 0x0a
59 private static final String CRLF = CR + LF; // 0x0d, 0x0a
61 private static final String PFX_SURFACEGROUP = "sg";
62 private static final String PFX_TOONFILE = "tf";
63 private static final String PFX_VERTEX = "vtx";
64 private static final String PFX_BONE = "bn";
65 private static final String PFX_RIGID = "rd";
66 private static final String PFX_RIGIDGROUP = "rg";
68 private static final String BONETYPE_COMMENT =
70 + "[0 : ROTATE : Rotate : 回転 :]\n"
71 + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n"
72 + "[2 : IK : IK : IK :]\n"
73 + "[3 : UNKNOWN : Unknown : 不明 :]\n"
74 + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n"
75 + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n"
76 + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n"
77 + "[7 : HIDDEN : Hidden : 非表示 :]\n"
78 + "[8 : TWIST : Twist : 捩り :]\n"
79 + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n";
81 private static final String MORPHTYPE_COMMENT =
83 + "[1 : EYEBROW : まゆ ]\n"
85 + "[3 : LIP : リップ ]\n"
86 + "[4 : EXTRA : その他 ]\n";
88 private static final String RIGIDBEHAVIOR_COMMENT =
89 "Rigid behavior types:\n"
90 + "[0 : FOLLOWBONE : ボーン追従 ]\n"
91 + "[1 : ONLYDYNAMICS : 物理演算 ]\n"
92 + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n";
94 private String generator = null;
96 private XmlModelFileType xmlType = XmlModelFileType.XML_101009;
101 * 文字エンコーディングはUTF-8が用いられる。
102 * @param stream 出力ストリーム
104 public XmlExporter(OutputStream stream){
113 public XmlModelFileType getXmlFileType(){
121 public void setXmlFileType(XmlModelFileType type){
128 this.xmlType = XmlModelFileType.XML_130128;
131 throw new IllegalArgumentException();
134 assert this.xmlType == XmlModelFileType.XML_101009
135 || this.xmlType == XmlModelFileType.XML_130128;
141 * Generatorメタ情報を設定する。
142 * @param generatorArg Generatorメタ情報。表示したくないときはnull
144 public void setGenerator(String generatorArg){
145 this.generator = generatorArg;
150 * 任意の文字列がBasicLatin文字のみから構成されるか判定する。
152 * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue
154 public static boolean hasOnlyBasicLatin(CharSequence seq){
155 if(seq == null) return true;
156 int length = seq.length();
157 for(int pos = 0; pos < length; pos++){
158 char ch = seq.charAt(pos);
159 if(ch > 0x007f) return false;
166 * @return {@inheritDoc}
167 * @throws IOException {@inheritDoc}
170 public XmlExporter ind() throws IOException{
176 * 文字参照によるエスケープを補佐するためのコメントを出力する。
179 * @throws IOException 出力エラー
181 protected XmlExporter putUnescapedComment(CharSequence seq)
183 if( ! isBasicLatinOnlyOut() ) return this;
184 if(hasOnlyBasicLatin(seq)) return this;
185 sp().putLineComment(seq);
194 * @throws IOException 出力エラー
196 protected XmlExporter putI18nName(I18nText text) throws IOException{
197 for(String lang639 : text.lang639CodeList()){
198 if(lang639.equals(I18nText.CODE639_PRIMARY)) continue;
199 String name = text.getI18nText(lang639);
200 ind().putRawText("<i18nName ");
201 putAttr("lang", lang639).sp();
202 putAttr("name", name);
204 putUnescapedComment(name);
211 * 番号付けされたID(IDREF)属性を出力する。
212 * @param attrName 属性名
213 * @param prefix IDプレフィクス
216 * @throws IOException 出力エラー
218 protected XmlExporter putNumberedIdAttr(CharSequence attrName,
222 putRawText(attrName).putRawText("=\"");
223 putRawText(prefix).putXsdInt(num);
229 * 番号付けされたID(IDREF)属性を出力する。
230 * @param attrName 属性名
231 * @param prefix IDプレフィクス
232 * @param numbered 番号付けされたオブジェクト
234 * @throws IOException 出力エラー
236 protected XmlExporter putNumberedIdAttr(CharSequence attrName,
238 SerialNumbered numbered )
240 putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber());
246 * @param position 位置情報
248 * @throws IOException 出力エラー
250 protected XmlExporter putPosition(MkPos3D position)
252 putRawText("<position ");
253 putFloatAttr("x", (float) position.getXpos()).sp();
254 putFloatAttr("y", (float) position.getYpos()).sp();
255 putFloatAttr("z", (float) position.getZpos()).sp();
262 * @param rotation 姿勢情報
264 * @throws IOException 出力エラー
266 protected XmlExporter putRadRotation(Rad3d rotation)
268 putRawText("<radRotation ");
269 putFloatAttr("xRad", rotation.getXRad()).sp();
270 putFloatAttr("yRad", rotation.getYRad()).sp();
271 putFloatAttr("zRad", rotation.getZRad()).sp();
277 * 多言語識別名属性のローカルな名前をコメント出力する。
280 * @throws IOException 出力エラー
282 protected XmlExporter putLocalNameComment(I18nText name)
284 String localName = name.getText();
285 if(localName.isEmpty()){
286 localName = "[NAMELESS]";
288 ind().putLineComment(localName);
293 * 多言語識別名属性のプライマリな名前を出力する。
294 * @param attrName 属性名
297 * @throws IOException 出力エラー
299 protected XmlExporter putPrimaryNameAttr(CharSequence attrName,
302 String primaryName = name.getPrimaryText();
303 putAttr(attrName, primaryName);
308 * PMDモデルデータをXML形式で出力する。
309 * @param model PMDモデルデータ
310 * @throws IOException 出力エラー
312 public void putPmdModel(PmdModel model) throws IOException{
313 ind().putRawText("<?xml")
314 .sp().putAttr("version","1.0")
315 .sp().putAttr("encoding","UTF-8")
316 .sp().putRawText("?>").ln(2);
318 ind().putBlockComment(TOP_COMMENT).ln(2);
320 I18nText modelName = model.getModelName();
321 ind().putLocalNameComment(modelName).ln();
322 ind().putRawText("<pmdModel").ln();
328 if(this.xmlType == XmlModelFileType.XML_101009){
329 defns = Schema101009.NS_PMDXML;
330 xsduri = Schema101009.SCHEMA_PMDXML;
331 version = Schema101009.VER_PMDXML;
332 }else if(this.xmlType == XmlModelFileType.XML_130128){
333 defns = Schema130128.NS_PMDXML;
334 xsduri = Schema130128.SCHEMA_PMDXML;
335 version = Schema130128.VER_PMDXML;
338 throw new AssertionError();
341 ind().putAttr("xmlns", defns).ln();
343 ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
345 ind().putRawText("xsi:schemaLocation").putRawText("=\"");
346 putRawText(defns).ln();
348 ind().putRawText(xsduri).putRawCh('"').ln();
351 ind().putAttr("schemaVersion", version).ln(2);
352 ind().putPrimaryNameAttr("name", modelName).ln();
355 putRawText(">").ln(2);
357 putModelInfo(model).flush();
358 putMetaInfo(model).flush();
359 putMaterialList(model).flush();
360 putToonMap(model).flush();
361 putBoneList(model).flush();
362 putBoneGroupList(model).flush();
363 putIKChainList(model).flush();
364 putMorphList(model).flush();
365 putRigidList(model).flush();
366 putRigidGroupList(model).flush();
367 putJointList(model).flush();
368 putSurfaceGroupList(model).flush();
369 putVertexList(model).flush();
371 ind().putRawText("</pmdModel>").ln(2);
372 ind().putRawText("<!-- EOF -->").ln();
381 * @throws IOException 出力エラー
383 private XmlExporter putModelInfo(PmdModel model)
385 I18nText modelName = model.getModelName();
386 putI18nName(modelName);
389 I18nText description = model.getDescription();
390 for(String lang639 : description.lang639CodeList()){
391 String descText = description.getI18nText(lang639);
392 putDescription(lang639, descText);
401 * @param lang639 言語コード
402 * @param content 詳細内容
404 * @throws IOException 出力エラー
406 private XmlExporter putDescription(CharSequence lang639,
407 CharSequence content)
409 String text = content.toString();
410 text = text.replace(CRLF, LF);
411 text = text.replace(CR, LF);
413 ind().putRawText("<description");
414 if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
415 sp().putAttr("lang", lang639).sp();
417 putRawText(">").ln();
419 putBRedContent(text);
421 ind().putRawText("</description>").ln();
423 if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){
424 putBlockComment(text);
431 * break要素を含む要素内容を出力する。
432 * 必要に応じてXML定義済み実体文字が割り振られた文字、
433 * コントロールコード、および非BasicLatin文字がエスケープされる。
437 * @throws IOException 出力エラー
439 protected BasicXmlExporter putBRedContent(CharSequence content)
441 int length = content.length();
445 for(int idx = 0; idx < length; idx++){
446 char ch = content.charAt(idx);
448 CharSequence seq = content.subSequence(startPos, idx);
449 putContent(seq).putRawText("<br/>").ln();
454 if(startPos < length){
455 CharSequence seq = content.subSequence(startPos, length);
456 putContent(seq).ln();
464 * @param model モデルデータ
466 * @throws IOException 出力エラー
468 private XmlExporter putMetaInfo(PmdModel model) throws IOException{
469 ind().putRawText("<license>").ln();
470 ind().putRawText("</license>").ln(2);
472 ind().putRawText("<credits>").ln();
473 ind().putRawText("</credits>").ln(2);
475 if(this.generator != null){
476 ind().putRawText("<meta ");
477 putAttr("name", "generator").sp()
478 .putAttr("content", this.generator);
479 putRawText(" />").ln();
482 ind().putRawText("<meta ");
483 putAttr("name", "siteURL").sp().putAttr("content", "");
484 putRawText(" />").ln();
485 ind().putRawText("<meta ");
486 putAttr("name", "imageURL").sp().putAttr("content", "");
487 putRawText(" />").ln(2);
494 * @param model モデルデータ
496 * @throws IOException 出力エラー
498 private XmlExporter putMaterialList(PmdModel model)
500 ind().putRawText("<materialList>").ln();
504 boolean dumped = false;
505 List<Material> materialList = model.getMaterialList();
506 for(Material material : materialList){
508 putMaterial(material, ct++);
513 ind().putRawText("</materialList>").ln(2);
520 * @param material マテリアル素材
521 * @param no マテリアル通し番号
523 * @throws IOException 出力エラー
525 private XmlExporter putMaterial(Material material, int no)
528 if(material.getEdgeAppearance()) bool = "true";
530 I18nText name = material.getMaterialName();
531 String primary = name.getPrimaryText();
532 String local = name.getText();
534 if(local != null && local.length() > 0){
535 ind().putLineComment(local).ln();
537 ind().putRawText("<material ");
538 if(primary != null && primary.length() > 0){
539 putAttr("name", primary).sp();
542 putAttr("showEdge", bool);
544 putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no);
545 sp().putRawCh('>').ln();
550 float[] rgba = new float[4];
552 Color diffuse = material.getDiffuseColor();
553 diffuse.getRGBComponents(rgba);
554 ind().putRawText("<diffuse ");
555 putFloatAttr("r", rgba[0]).sp();
556 putFloatAttr("g", rgba[1]).sp();
557 putFloatAttr("b", rgba[2]).sp();
558 putFloatAttr("alpha", rgba[3]).sp();
559 putRawText("/>").ln();
561 Color specular = material.getSpecularColor();
562 specular.getRGBComponents(rgba);
563 float shininess = material.getShininess();
564 ind().putRawText("<specular ");
565 putFloatAttr("r", rgba[0]).sp();
566 putFloatAttr("g", rgba[1]).sp();
567 putFloatAttr("b", rgba[2]).sp();
568 putFloatAttr("shininess", shininess).sp();
569 putRawText("/>").ln();
571 Color ambient = material.getAmbientColor();
572 ambient.getRGBComponents(rgba);
573 ind().putRawText("<ambient ");
574 putFloatAttr("r", rgba[0]).sp();
575 putFloatAttr("g", rgba[1]).sp();
576 putFloatAttr("b", rgba[2]).sp();
577 putRawText("/>").ln();
579 ShadeInfo shade = material.getShadeInfo();
580 String textureFileName = shade.getTextureFileName();
581 String spheremapFileName = shade.getSpheremapFileName();
583 if(shade.isValidToonIndex()){
584 ind().putRawText("<toon ");
585 int toonIdx = shade.getToonIndex();
586 putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
588 String toonFileName = shade.getToonFileName();
589 if(toonFileName != null && toonFileName.length() > 0){
590 sp().putLineComment(toonFileName);
595 if(textureFileName != null && textureFileName.length() > 0){
596 ind().putRawText("<textureFile ");
597 putAttr("winFileName", textureFileName);
598 putRawText(" />").ln();
601 if(spheremapFileName != null && spheremapFileName.length() > 0){
602 ind().putRawText("<spheremapFile ");
603 putAttr("winFileName", spheremapFileName);
604 putRawText(" />").ln();
608 ind().putRawText("</material>").ln(2);
614 * トゥーンファイルマッピング情報を出力する。
615 * @param model モデルデータ
617 * @throws IOException 出力エラー
619 private XmlExporter putToonMap(PmdModel model)
621 ind().putRawText("<toonMap>").ln();
624 ToonMap map = model.getToonMap();
625 for(int index = 0; index <= 9; index++){
626 ind().putToon(map, index).ln();
630 ind().putRawText("</toonMap>").ln(2);
635 * 個別のトゥーンファイル情報を出力する。
637 * @param index インデックス値
639 * @throws IOException 出力エラー
641 private XmlExporter putToon(ToonMap map, int index)
643 putRawText("<toonDef ");
644 putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).sp();
645 putIntAttr("index", index).sp();
646 String toonFile = map.getIndexedToon(index);
647 putAttr("winFileName", toonFile);
649 putUnescapedComment(toonFile);
654 * サーフェイスグループリストを出力する。
655 * @param model モデルデータ
657 * @throws IOException 出力エラー
659 private XmlExporter putSurfaceGroupList(PmdModel model)
661 ind().putRawText("<surfaceGroupList>").ln();
665 boolean dumped = false;
666 List<Material> materialList = model.getMaterialList();
667 for(Material material : materialList){
668 List<Surface> surfaceList = material.getSurfaceList();
670 putSurfaceList(surfaceList, ct++);
675 ind().putRawText("</surfaceGroupList>").ln(2);
681 * 個別のサーフェイスグループを出力する。
682 * @param surfaceList サーフェイスのリスト
683 * @param index グループインデックス
685 * @throws IOException 出力エラー
687 private XmlExporter putSurfaceList(List<Surface> surfaceList,
690 ind().putRawText("<surfaceGroup ");
691 putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
692 sp().putRawText(">").ln();
695 for(Surface surface : surfaceList){
700 ind().putRawText("</surfaceGroup>").ln(2);
707 * @param surface サーフェイス
709 * @throws IOException 出力エラー
711 private XmlExporter putSurface(Surface surface)
713 ind().putRawText("<surface ");
715 Vertex vertex1 = surface.getVertex1();
716 Vertex vertex2 = surface.getVertex2();
717 Vertex vertex3 = surface.getVertex3();
719 putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).sp();
720 putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).sp();
721 putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).sp();
723 putRawText("/>").ln();
729 * @param model モデルデータ
731 * @throws IOException 出力エラー
733 private XmlExporter putVertexList(PmdModel model)
735 ind().putRawText("<vertexList>").ln();
738 boolean dumped = false;
739 List<Vertex> vertexList = model.getVertexList();
740 for(Vertex vertex : vertexList){
747 ind().putRawText("</vertexList>").ln(2);
756 * @throws IOException 出力エラー
758 private XmlExporter putVertex(Vertex vertex)
761 if(vertex.getEdgeAppearance()) bool = "true";
764 ind().putRawText("<vertex ");
765 putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).sp();
766 putAttr("showEdge", bool);
767 sp().putRawText(">").ln();
770 MkPos3D position = vertex.getPosition();
771 ind().putPosition(position).ln();
773 MkVec3D normal = vertex.getNormal();
774 ind().putRawText("<normal ");
775 putFloatAttr("x", (float) normal.getXVal()).sp();
776 putFloatAttr("y", (float) normal.getYVal()).sp();
777 putFloatAttr("z", (float) normal.getZVal()).sp();
778 putRawText("/>").ln();
780 MkPos2D uvPos = vertex.getUVPosition();
781 ind().putRawText("<uvMap ");
782 putFloatAttr("u", (float) uvPos.getXpos()).sp();
783 putFloatAttr("v", (float) uvPos.getYpos()).sp();
784 putRawText("/>").ln();
786 BoneInfo boneA = vertex.getBoneA();
787 BoneInfo boneB = vertex.getBoneB();
788 int weight = vertex.getWeightA();
789 ind().putRawText("<skinning ");
790 putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).sp();
791 putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).sp();
792 putIntAttr("weightBalance", weight).sp();
793 putRawText("/>").ln();
796 ind().putRawText("</vertex>").ln(2);
803 * @param model モデルデータ
805 * @throws IOException 出力エラー
807 private XmlExporter putBoneList(PmdModel model)
809 ind().putRawText("<boneList>").ln();
812 boolean dumped = false;
813 for(BoneInfo bone : model.getBoneList()){
815 ln().putBlockComment(BONETYPE_COMMENT).ln();
822 ind().putRawText("</boneList>").ln(2);
831 * @throws IOException 出力エラー
833 private XmlExporter putBone(BoneInfo bone)
835 I18nText i18nName = bone.getBoneName();
836 BoneType type = bone.getBoneType();
838 StringBuilder boneComment = new StringBuilder();
839 String boneName = i18nName.getText();
840 if(boneName.isEmpty()){
841 boneName = "[NAMELESS]";
843 boneComment.append(boneName);
844 String typeName = type.getGuiName();
845 boneComment.append(" [").append(typeName).append(']');
846 ind().putLineComment(boneComment.toString()).ln();
848 ind().putRawText("<bone ");
849 putPrimaryNameAttr("name", i18nName).sp();
850 putNumberedIdAttr("boneId", PFX_BONE, bone).sp();
851 putAttr("type", type.name());
852 sp().putRawText(">").ln();
855 putI18nName(i18nName);
857 MkPos3D position = bone.getPosition();
858 ind().putPosition(position).ln();
860 BoneInfo srcBone = bone.getSrcBone();
861 if(bone.getBoneType() == BoneType.LINKEDROT){
862 ind().putRawText("<rotationRatio ");
863 putIntAttr("ratio", bone.getRotationRatio());
864 putRawText(" />").ln();
865 }else if(srcBone != null){
867 switch(getXmlFileType()){
872 iktag = "<sourceBone ";
876 throw new AssertionError();
878 ind().putRawText(iktag);
879 putNumberedIdAttr("boneIdRef", PFX_BONE, srcBone);
881 String ikBoneName = "Ref:" + srcBone.getBoneName().getText();
882 putLineComment(ikBoneName);
886 BoneInfo prev = bone.getPrevBone();
887 BoneInfo next = bone.getNextBone();
889 StringBuilder chainComment = new StringBuilder();
891 chainComment.append('[')
892 .append(prev.getBoneName().getPrimaryText())
897 if(chainComment.length() <= 0) chainComment.append("#");
898 chainComment.append(">> ")
900 .append(next.getBoneName().getPrimaryText())
903 if(chainComment.length() > 0){
905 ind().putLineComment(chainComment).ln();
908 ind().putRawText("<boneChain");
911 putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
915 putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
917 putRawText(" />").ln();
920 ind().putRawText("</bone>").ln(2);
927 * @param model モデルデータ
929 * @throws IOException 出力エラー
931 private XmlExporter putBoneGroupList(PmdModel model)
933 ind().putRawText("<boneGroupList>").ln();
936 boolean dumped = false;
937 List<BoneGroup> groupList = model.getBoneGroupList();
938 for(BoneGroup group : groupList){
939 if(group.isDefaultBoneGroup()) continue;
946 ind().putRawText("</boneGroupList>").ln(2);
953 * @param group ボーングループ情報
955 * @throws IOException 出力エラー
957 private XmlExporter putBoneGroup(BoneGroup group)
959 I18nText i18nName = group.getGroupName();
961 putLocalNameComment(i18nName).ln();
962 ind().putRawText("<boneGroup ");
963 putPrimaryNameAttr("name", i18nName);
964 sp().putRawText(">").ln();
967 putI18nName(i18nName);
969 for(BoneInfo bone : group){
970 ind().putRawText("<boneGroupMember ");
971 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
973 String boneName = "Ref:" + bone.getBoneName().getText();
974 putLineComment(boneName).ln();
978 ind().putRawText("</boneGroup>").ln(2);
985 * @param model モデルデータ
987 * @throws IOException 出力エラー
989 private XmlExporter putIKChainList(PmdModel model)
991 ind().putRawText("<ikChainList>").ln();
994 boolean dumped = false;
995 List<IKChain> chainList = model.getIKChainList();
996 for(IKChain chain : chainList){
1003 ind().putRawText("</ikChainList>").ln(2);
1010 * @param chain チェーン情報
1012 * @throws IOException 出力エラー
1014 private XmlExporter putIKChain(IKChain chain)
1016 int depth = chain.getIKDepth();
1017 float weight = chain.getIKWeight();
1018 BoneInfo ikBone = chain.getIkBone();
1020 ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln();
1021 ind().putRawText("<ikChain ");
1022 putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).sp();
1023 putIntAttr("recursiveDepth", depth).sp();
1024 putFloatAttr("weight", weight);
1025 sp().putRawText(">").ln();
1028 for(BoneInfo bone : chain){
1029 ind().putRawText("<chainOrder ");
1030 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
1032 putLineComment("Ref:" + bone.getBoneName().getText());
1037 ind().putRawText("</ikChain>").ln(2);
1044 * @param model モデルデータ
1046 * @throws IOException 出力エラー
1048 private XmlExporter putMorphList(PmdModel model)
1050 ind().putRawText("<morphList>").ln();
1053 boolean dumped = false;
1054 Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
1055 for(MorphType type : MorphType.values()){
1056 if(type == MorphType.BASE) continue;
1057 List<MorphPart> partList = morphMap.get(type);
1058 if(partList == null) continue;
1059 for(MorphPart part : partList){
1061 ln().putBlockComment(MORPHTYPE_COMMENT).ln();
1069 ind().putRawText("</morphList>").ln(2);
1078 * @throws IOException 出力エラー
1080 private XmlExporter putMorphPart(MorphPart part)
1082 I18nText i18nName = part.getMorphName();
1083 String primary = i18nName.getPrimaryText();
1085 putLocalNameComment(i18nName).ln();
1086 ind().putRawText("<morph ");
1087 putAttr("name", primary).sp();
1088 putAttr("type", part.getMorphType().name());
1089 sp().putRawText(">");
1093 putI18nName(i18nName);
1095 for(MorphVertex mvertex : part){
1096 MkPos3D offset = mvertex.getOffset();
1097 Vertex base = mvertex.getBaseVertex();
1099 ind().putRawText("<morphVertex ");
1100 putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).sp();
1101 putFloatAttr("xOff", (float) offset.getXpos()).sp();
1102 putFloatAttr("yOff", (float) offset.getYpos()).sp();
1103 putFloatAttr("zOff", (float) offset.getZpos()).sp();
1109 ind().putRawText("</morph>").ln(2);
1116 * @param model モデルデータ
1118 * @throws IOException 出力エラー
1120 private XmlExporter putRigidList(PmdModel model)
1122 ind().putRawText("<rigidList>").ln();
1125 boolean dumped = false;
1126 for(RigidInfo rigid : model.getRigidList()){
1128 ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
1135 ind().putRawText("</rigidList>").ln(2);
1144 * @throws IOException 出力エラー
1146 private XmlExporter putRigid(RigidInfo rigid)
1148 BoneInfo linkedBone = rigid.getLinkedBone();
1149 I18nText i18nName = rigid.getRigidName();
1150 String primary = i18nName.getPrimaryText();
1152 putLocalNameComment(i18nName).ln();
1153 ind().putRawText("<rigid ");
1154 putAttr("name", primary).sp();
1155 putNumberedIdAttr("rigidId", PFX_RIGID, rigid).sp();
1156 putAttr("behavior", rigid.getBehaviorType().name());
1157 sp().putRawText(">").ln();
1160 putI18nName(i18nName);
1162 if(linkedBone != null){
1163 ind().putRawText("<linkedBone ");
1164 putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
1166 putLineComment("Ref:" + linkedBone.getBoneName().getText());
1170 RigidShape shape = rigid.getRigidShape();
1171 putRigidShape(shape);
1173 MkPos3D position = rigid.getPosition();
1174 ind().putPosition(position).ln();
1176 Rad3d rotation = rigid.getRotation();
1177 ind().putRadRotation(rotation).ln();
1179 DynamicsInfo dynamics = rigid.getDynamicsInfo();
1180 putDynamics(dynamics).ln();
1182 for(RigidGroup group : rigid.getThroughGroupColl()){
1183 ind().putRawText("<throughRigidGroup ");
1184 putNumberedIdAttr("rigidGroupIdRef",
1186 group.getSerialNumber() + 1).sp();
1187 putRawText(" />").ln();
1191 ind().putRawText("</rigid>").ln(2);
1200 * @throws IOException 出力エラー
1202 private XmlExporter putRigidShape(RigidShape shape)
1204 RigidShapeType type = shape.getShapeType();
1208 ind().putRawText("<rigidShapeBox ");
1209 putFloatAttr("width", shape.getWidth()).sp();
1210 putFloatAttr("height", shape.getHeight()).sp();
1211 putFloatAttr("depth", shape.getDepth()).sp();
1214 ind().putRawText("<rigidShapeSphere ");
1215 putFloatAttr("radius", shape.getRadius()).sp();
1218 ind().putRawText("<rigidShapeCapsule ");
1219 putFloatAttr("height", shape.getHeight()).sp();
1220 putFloatAttr("radius", shape.getRadius()).sp();
1224 throw new AssertionError();
1227 putRawText("/>").ln();
1234 * @param dynamics 力学設定
1236 * @throws IOException 出力エラー
1238 private XmlExporter putDynamics(DynamicsInfo dynamics)
1240 ind().putRawText("<dynamics").ln();
1242 ind().putFloatAttr("mass", dynamics.getMass()).ln();
1243 ind().putFloatAttr("dampingPosition",
1244 dynamics.getDampingPosition()).ln();
1245 ind().putFloatAttr("dampingRotation",
1246 dynamics.getDampingRotation()).ln();
1247 ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
1248 ind().putFloatAttr("friction", dynamics.getFriction()).ln();
1250 ind().putRawText("/>").ln();
1257 * @param model モデルデータ
1259 * @throws IOException 出力エラー
1261 private XmlExporter putRigidGroupList(PmdModel model)
1263 ind().putRawText("<rigidGroupList>").ln(2);
1266 boolean singleLast = false;
1267 for(RigidGroup group : model.getRigidGroupList()){
1268 List<RigidInfo> rigidList = group.getRigidList();
1269 if(singleLast && ! rigidList.isEmpty()){
1272 ind().putRawText("<rigidGroup ");
1273 putNumberedIdAttr("rigidGroupId",
1275 group.getSerialNumber() + 1);
1276 if(rigidList.isEmpty()){
1277 putRawText(" />").ln();
1281 putRawText(" >").ln();
1284 for(RigidInfo rigid : rigidList){
1285 ind().putRawText("<rigidGroupMember ");
1286 putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).sp();
1289 putLineComment("Ref:" + rigid.getRigidName().getText());
1294 ind().putRawText("</rigidGroup>").ln(2);
1303 ind().putRawText("</rigidGroupList>").ln(2);
1310 * @param model モデルデータ
1312 * @throws IOException 出力エラー
1314 private XmlExporter putJointList(PmdModel model)
1316 ind().putRawText("<jointList>").ln();
1319 boolean dumped = false;
1320 List<JointInfo> jointList = model.getJointList();
1321 for(JointInfo joint : jointList){
1322 if( ! dumped ) ln();
1328 ind().putRawText("</jointList>").ln(2);
1335 * @param joint ジョイント情報
1337 * @throws IOException 出力エラー
1339 private XmlExporter putJoint(JointInfo joint)
1341 I18nText i18nName = joint.getJointName();
1343 putLocalNameComment(i18nName).ln();
1344 ind().putRawText("<joint ");
1345 putPrimaryNameAttr("name", i18nName);
1346 sp().putRawText(">").ln();
1349 putI18nName(i18nName);
1351 RigidInfo rigidA = joint.getRigidA();
1352 RigidInfo rigidB = joint.getRigidB();
1355 putLineComment("[" + rigidA.getRigidName().getText() + "]"
1356 + " <=> [" + rigidB.getRigidName().getText() + "]");
1359 ind().putRawText("<jointedRigidPair ");
1360 putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).sp();
1361 putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).sp();
1362 putRawText("/>").ln(2);
1364 MkPos3D position = joint.getPosition();
1365 ind().putPosition(position).ln();
1367 TripletRange posRange = joint.getPositionRange();
1368 ind().putRawText("<limitPosition").ln();
1371 putFloatAttr("xFrom", posRange.getXFrom()).sp();
1372 putFloatAttr("xTo", posRange.getXTo()).ln();
1374 putFloatAttr("yFrom", posRange.getYFrom()).sp();
1375 putFloatAttr("yTo", posRange.getYTo()).ln();
1377 putFloatAttr("zFrom", posRange.getZFrom()).sp();
1378 putFloatAttr("zTo", posRange.getZTo()).ln();
1380 ind().putRawText("/>").ln(2);
1382 Rad3d rotation = joint.getRotation();
1383 ind().putRadRotation(rotation).ln();
1384 TripletRange rotRange = joint.getRotationRange();
1385 ind().putRawText("<limitRotation").ln();
1388 putFloatAttr("xFrom", rotRange.getXFrom()).sp();
1389 putFloatAttr("xTo", rotRange.getXTo()).ln();
1391 putFloatAttr("yFrom", rotRange.getYFrom()).sp();
1392 putFloatAttr("yTo", rotRange.getYTo()).ln();
1394 putFloatAttr("zFrom", rotRange.getZFrom()).sp();
1395 putFloatAttr("zTo", rotRange.getZTo()).ln();
1397 ind().putRawText("/>").ln(2);
1399 MkPos3D elaPosition = joint.getElasticPosition();
1400 ind().putRawText("<elasticPosition ");
1401 putFloatAttr("x", (float) elaPosition.getXpos()).sp();
1402 putFloatAttr("y", (float) elaPosition.getYpos()).sp();
1403 putFloatAttr("z", (float) elaPosition.getZpos()).sp();
1404 putRawText("/>").ln();
1406 Deg3d elaRotation = joint.getElasticRotation();
1407 ind().putRawText("<elasticRotation ");
1408 putFloatAttr("xDeg", elaRotation.getXDeg()).sp();
1409 putFloatAttr("yDeg", elaRotation.getYDeg()).sp();
1410 putFloatAttr("zDeg", elaRotation.getZDeg()).sp();
1411 putRawText("/>").ln(2);
1414 ind().putRawText("</joint>").ln(2);