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;
14 import java.util.Locale;
16 import jp.sfjp.mikutoga.corelib.I18nText;
17 import jp.sfjp.mikutoga.math.MkPos2D;
18 import jp.sfjp.mikutoga.math.MkPos3D;
19 import jp.sfjp.mikutoga.math.MkVec3D;
20 import jp.sfjp.mikutoga.pmd.BoneType;
21 import jp.sfjp.mikutoga.pmd.Deg3d;
22 import jp.sfjp.mikutoga.pmd.MorphType;
23 import jp.sfjp.mikutoga.pmd.Rad3d;
24 import jp.sfjp.mikutoga.pmd.RigidShapeType;
25 import jp.sfjp.mikutoga.pmd.TripletRange;
26 import jp.sfjp.mikutoga.pmd.model.BoneGroup;
27 import jp.sfjp.mikutoga.pmd.model.BoneInfo;
28 import jp.sfjp.mikutoga.pmd.model.DynamicsInfo;
29 import jp.sfjp.mikutoga.pmd.model.IKChain;
30 import jp.sfjp.mikutoga.pmd.model.JointInfo;
31 import jp.sfjp.mikutoga.pmd.model.Material;
32 import jp.sfjp.mikutoga.pmd.model.MorphPart;
33 import jp.sfjp.mikutoga.pmd.model.MorphVertex;
34 import jp.sfjp.mikutoga.pmd.model.PmdModel;
35 import jp.sfjp.mikutoga.pmd.model.RigidGroup;
36 import jp.sfjp.mikutoga.pmd.model.RigidInfo;
37 import jp.sfjp.mikutoga.pmd.model.RigidShape;
38 import jp.sfjp.mikutoga.pmd.model.SerialNumbered;
39 import jp.sfjp.mikutoga.pmd.model.ShadeInfo;
40 import jp.sfjp.mikutoga.pmd.model.Surface;
41 import jp.sfjp.mikutoga.pmd.model.ToonMap;
42 import jp.sfjp.mikutoga.pmd.model.Vertex;
43 import jp.sourceforge.mikutoga.xml.BasicXmlExporter;
44 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
47 * 101009形式XMLでPMDモデルデータを出力する。
49 public class XmlExporter extends BasicXmlExporter{
51 private static final String TOP_COMMENT =
53 + " model-data(*.pmd) on XML";
56 private static final String CR = "\r"; // 0x0d
58 private static final String LF = "\n"; // 0x0a
60 private static final String CRLF = CR + LF; // 0x0d, 0x0a
62 private static final String PFX_SURFACEGROUP = "sg";
63 private static final String PFX_TOONFILE = "tf";
64 private static final String PFX_VERTEX = "vtx";
65 private static final String PFX_BONE = "bn";
66 private static final String PFX_RIGID = "rd";
67 private static final String PFX_RIGIDGROUP = "rg";
69 private static final String BONETYPE_COMMENT =
71 + "[0 : ROTATE : Rotate : 回転 :]\n"
72 + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n"
73 + "[2 : IK : IK : IK :]\n"
74 + "[3 : UNKNOWN : Unknown : 不明 :]\n"
75 + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n"
76 + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n"
77 + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n"
78 + "[7 : HIDDEN : Hidden : 非表示 :]\n"
79 + "[8 : TWIST : Twist : 捩り :]\n"
80 + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n";
82 private static final String MORPHTYPE_COMMENT =
84 + "[1 : EYEBROW : まゆ ]\n"
86 + "[3 : LIP : リップ ]\n"
87 + "[4 : EXTRA : その他 ]\n";
89 private static final String RIGIDBEHAVIOR_COMMENT =
90 "Rigid behavior types:\n"
91 + "[0 : FOLLOWBONE : ボーン追従 ]\n"
92 + "[1 : ONLYDYNAMICS : 物理演算 ]\n"
93 + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n";
95 private static final Locale DEF_LOCALE = Locale.JAPANESE;
98 private String generator = null;
100 private XmlModelFileType xmlType = XmlModelFileType.XML_101009;
105 * 文字エンコーディングはUTF-8が用いられる。
106 * @param stream 出力ストリーム
108 public XmlExporter(OutputStream stream){
117 public XmlModelFileType getXmlFileType(){
125 public void setXmlFileType(XmlModelFileType type){
132 this.xmlType = XmlModelFileType.XML_130128;
135 throw new IllegalArgumentException();
138 assert this.xmlType == XmlModelFileType.XML_101009
139 || this.xmlType == XmlModelFileType.XML_130128;
145 * Generatorメタ情報を設定する。
146 * @param generatorArg Generatorメタ情報。表示したくないときはnull
148 public void setGenerator(String generatorArg){
149 this.generator = generatorArg;
154 * 任意の文字列がBasicLatin文字のみから構成されるか判定する。
156 * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue
158 public static boolean hasOnlyBasicLatin(CharSequence seq){
159 if(seq == null) return true;
160 int length = seq.length();
161 for(int pos = 0; pos < length; pos++){
162 char ch = seq.charAt(pos);
163 if(ch > 0x007f) return false;
170 * @return {@inheritDoc}
171 * @throws IOException {@inheritDoc}
174 public XmlExporter ind() throws IOException{
180 * 文字参照によるエスケープを補佐するためのコメントを出力する。
183 * @throws IOException 出力エラー
185 protected XmlExporter putUnescapedComment(CharSequence seq)
187 if( ! isBasicLatinOnlyOut() ) return this;
188 if(hasOnlyBasicLatin(seq)) return this;
189 sp().putLineComment(seq);
198 * @throws IOException 出力エラー
200 protected XmlExporter putI18nName(I18nText text) throws IOException{
201 for(String lang639 : text.lang639CodeList()){
202 if(lang639.equals(I18nText.CODE639_PRIMARY)) continue;
203 String name = text.getI18nText(lang639);
204 ind().putRawText("<i18nName ");
205 putAttr("lang", lang639).sp();
206 putAttr("name", name);
208 putUnescapedComment(name);
215 * 番号付けされたID(IDREF)属性を出力する。
216 * @param attrName 属性名
217 * @param prefix IDプレフィクス
220 * @throws IOException 出力エラー
222 protected XmlExporter putNumberedIdAttr(CharSequence attrName,
226 putRawText(attrName).putRawText("=\"");
227 putRawText(prefix).putXsdInt(num);
233 * 番号付けされたID(IDREF)属性を出力する。
234 * @param attrName 属性名
235 * @param prefix IDプレフィクス
236 * @param numbered 番号付けされたオブジェクト
238 * @throws IOException 出力エラー
240 protected XmlExporter putNumberedIdAttr(CharSequence attrName,
242 SerialNumbered numbered )
244 putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber());
250 * @param position 位置情報
252 * @throws IOException 出力エラー
254 protected XmlExporter putPosition(MkPos3D position)
256 putRawText("<position ");
257 putFloatAttr("x", (float) position.getXpos()).sp();
258 putFloatAttr("y", (float) position.getYpos()).sp();
259 putFloatAttr("z", (float) position.getZpos()).sp();
266 * @param rotation 姿勢情報
268 * @throws IOException 出力エラー
270 protected XmlExporter putRadRotation(Rad3d rotation)
272 putRawText("<radRotation ");
273 putFloatAttr("xRad", rotation.getXRad()).sp();
274 putFloatAttr("yRad", rotation.getYRad()).sp();
275 putFloatAttr("zRad", rotation.getZRad()).sp();
281 * 多言語識別名属性のローカルな名前をコメント出力する。
284 * @throws IOException 出力エラー
286 protected XmlExporter putLocalNameComment(I18nText name)
288 String localName = name.getText();
289 if(localName.isEmpty()){
290 localName = "[NAMELESS]";
292 ind().putLineComment(localName);
297 * 多言語識別名属性のプライマリな名前を出力する。
298 * @param attrName 属性名
301 * @throws IOException 出力エラー
303 protected XmlExporter putPrimaryNameAttr(CharSequence attrName,
306 String primaryName = name.getPrimaryText();
307 putAttr(attrName, primaryName);
312 * PMDモデルデータをXML形式で出力する。
313 * @param model PMDモデルデータ
314 * @throws IOException 出力エラー
316 public void putPmdModel(PmdModel model) throws IOException{
317 ind().putRawText("<?xml")
318 .sp().putAttr("version","1.0")
319 .sp().putAttr("encoding","UTF-8")
320 .sp().putRawText("?>").ln(2);
322 ind().putBlockComment(TOP_COMMENT).ln(2);
324 I18nText modelName = model.getModelName();
325 ind().putLocalNameComment(modelName).ln();
326 ind().putRawText("<pmdModel").ln();
332 if(this.xmlType == XmlModelFileType.XML_101009){
333 defns = Schema101009.NS_PMDXML;
334 xsduri = Schema101009.SCHEMA_PMDXML;
335 version = Schema101009.VER_PMDXML;
336 }else if(this.xmlType == XmlModelFileType.XML_130128){
337 defns = Schema130128.NS_PMDXML;
338 xsduri = Schema130128.SCHEMA_PMDXML;
339 version = Schema130128.VER_PMDXML;
342 throw new AssertionError();
345 ind().putAttr("xmlns", defns).ln();
347 ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
349 ind().putRawText("xsi:schemaLocation").putRawText("=\"");
350 putRawText(defns).ln();
352 ind().putRawText(xsduri).putRawCh('"').ln();
355 ind().putAttr("schemaVersion", version).ln(2);
356 ind().putPrimaryNameAttr("name", modelName).ln();
359 putRawText(">").ln(2);
361 putModelInfo(model).flush();
362 putMetaInfo(model).flush();
363 putMaterialList(model).flush();
364 putToonMap(model).flush();
365 putBoneList(model).flush();
366 putBoneGroupList(model).flush();
367 putIKChainList(model).flush();
368 putMorphList(model).flush();
369 putRigidList(model).flush();
370 putRigidGroupList(model).flush();
371 putJointList(model).flush();
372 putSurfaceGroupList(model).flush();
373 putVertexList(model).flush();
375 ind().putRawText("</pmdModel>").ln(2);
376 ind().putRawText("<!-- EOF -->").ln();
385 * @throws IOException 出力エラー
387 private XmlExporter putModelInfo(PmdModel model)
389 I18nText modelName = model.getModelName();
390 putI18nName(modelName);
393 I18nText description = model.getDescription();
394 for(String lang639 : description.lang639CodeList()){
395 String descText = description.getI18nText(lang639);
396 putDescription(lang639, descText);
405 * @param lang639 言語コード
406 * @param content 詳細内容
408 * @throws IOException 出力エラー
410 private XmlExporter putDescription(CharSequence lang639,
411 CharSequence content)
413 String text = content.toString();
414 text = text.replace(CRLF, LF);
415 text = text.replace(CR, LF);
417 ind().putRawText("<description");
418 if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
419 sp().putAttr("lang", lang639).sp();
421 putRawText(">").ln();
423 putBRedContent(text);
425 ind().putRawText("</description>").ln();
427 if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){
428 putBlockComment(text);
435 * break要素を含む要素内容を出力する。
436 * 必要に応じてXML定義済み実体文字が割り振られた文字、
437 * コントロールコード、および非BasicLatin文字がエスケープされる。
441 * @throws IOException 出力エラー
443 protected BasicXmlExporter putBRedContent(CharSequence content)
445 int length = content.length();
449 for(int idx = 0; idx < length; idx++){
450 char ch = content.charAt(idx);
452 CharSequence seq = content.subSequence(startPos, idx);
453 putContent(seq).putRawText("<br/>").ln();
458 if(startPos < length){
459 CharSequence seq = content.subSequence(startPos, length);
460 putContent(seq).ln();
468 * @param model モデルデータ
470 * @throws IOException 出力エラー
472 private XmlExporter putMetaInfo(PmdModel model) throws IOException{
473 ind().putRawText("<license>").ln();
474 ind().putRawText("</license>").ln(2);
476 ind().putRawText("<credits>").ln();
477 ind().putRawText("</credits>").ln(2);
479 if(this.generator != null){
480 ind().putRawText("<meta ");
481 putAttr("name", "generator").sp()
482 .putAttr("content", this.generator);
483 putRawText(" />").ln();
486 ind().putRawText("<meta ");
487 putAttr("name", "siteURL").sp().putAttr("content", "");
488 putRawText(" />").ln();
489 ind().putRawText("<meta ");
490 putAttr("name", "imageURL").sp().putAttr("content", "");
491 putRawText(" />").ln(2);
498 * @param model モデルデータ
500 * @throws IOException 出力エラー
502 private XmlExporter putMaterialList(PmdModel model)
504 ind().putRawText("<materialList>").ln();
508 boolean dumped = false;
509 List<Material> materialList = model.getMaterialList();
510 for(Material material : materialList){
512 putMaterial(material, ct++);
517 ind().putRawText("</materialList>").ln(2);
524 * @param material マテリアル素材
525 * @param no マテリアル通し番号
527 * @throws IOException 出力エラー
529 private XmlExporter putMaterial(Material material, int no)
532 if(material.getEdgeAppearance()) bool = "true";
534 I18nText name = material.getMaterialName();
535 String primary = name.getPrimaryText();
536 String local = name.getText();
538 if(local != null && local.length() > 0){
539 ind().putLineComment(local).ln();
541 ind().putRawText("<material ");
542 if(primary != null && primary.length() > 0){
543 putAttr("name", primary).sp();
546 putAttr("showEdge", bool);
548 putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no);
549 sp().putRawCh('>').ln();
554 float[] rgba = new float[4];
556 Color diffuse = material.getDiffuseColor();
557 diffuse.getRGBComponents(rgba);
558 ind().putRawText("<diffuse ");
559 putFloatAttr("r", rgba[0]).sp();
560 putFloatAttr("g", rgba[1]).sp();
561 putFloatAttr("b", rgba[2]).sp();
562 putFloatAttr("alpha", rgba[3]).sp();
563 putRawText("/>").ln();
565 Color specular = material.getSpecularColor();
566 specular.getRGBComponents(rgba);
567 float shininess = material.getShininess();
568 ind().putRawText("<specular ");
569 putFloatAttr("r", rgba[0]).sp();
570 putFloatAttr("g", rgba[1]).sp();
571 putFloatAttr("b", rgba[2]).sp();
572 putFloatAttr("shininess", shininess).sp();
573 putRawText("/>").ln();
575 Color ambient = material.getAmbientColor();
576 ambient.getRGBComponents(rgba);
577 ind().putRawText("<ambient ");
578 putFloatAttr("r", rgba[0]).sp();
579 putFloatAttr("g", rgba[1]).sp();
580 putFloatAttr("b", rgba[2]).sp();
581 putRawText("/>").ln();
583 ShadeInfo shade = material.getShadeInfo();
584 String textureFileName = shade.getTextureFileName();
585 String spheremapFileName = shade.getSpheremapFileName();
587 if(shade.isValidToonIndex()){
588 ind().putRawText("<toon ");
589 int toonIdx = shade.getToonIndex();
590 putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
592 String toonFileName = shade.getToonFileName();
593 if(toonFileName != null && toonFileName.length() > 0){
594 sp().putLineComment(toonFileName);
599 if(textureFileName != null && textureFileName.length() > 0){
600 ind().putRawText("<textureFile ");
601 putAttr("winFileName", textureFileName);
602 putRawText(" />").ln();
605 if(spheremapFileName != null && spheremapFileName.length() > 0){
606 ind().putRawText("<spheremapFile ");
607 putAttr("winFileName", spheremapFileName);
608 putRawText(" />").ln();
612 ind().putRawText("</material>").ln(2);
618 * トゥーンファイルマッピング情報を出力する。
619 * @param model モデルデータ
621 * @throws IOException 出力エラー
623 private XmlExporter putToonMap(PmdModel model)
625 ind().putRawText("<toonMap>").ln();
628 ToonMap map = model.getToonMap();
629 for(int index = 0; index <= 9; index++){
630 ind().putToon(map, index).ln();
634 ind().putRawText("</toonMap>").ln(2);
639 * 個別のトゥーンファイル情報を出力する。
641 * @param index インデックス値
643 * @throws IOException 出力エラー
645 private XmlExporter putToon(ToonMap map, int index)
647 putRawText("<toonDef ");
648 putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).sp();
649 putIntAttr("index", index).sp();
650 String toonFile = map.getIndexedToon(index);
651 putAttr("winFileName", toonFile);
653 putUnescapedComment(toonFile);
658 * サーフェイスグループリストを出力する。
659 * @param model モデルデータ
661 * @throws IOException 出力エラー
663 private XmlExporter putSurfaceGroupList(PmdModel model)
665 ind().putRawText("<surfaceGroupList>").ln();
669 boolean dumped = false;
670 List<Material> materialList = model.getMaterialList();
671 for(Material material : materialList){
672 List<Surface> surfaceList = material.getSurfaceList();
674 putSurfaceList(surfaceList, ct++);
679 ind().putRawText("</surfaceGroupList>").ln(2);
685 * 個別のサーフェイスグループを出力する。
686 * @param surfaceList サーフェイスのリスト
687 * @param index グループインデックス
689 * @throws IOException 出力エラー
691 private XmlExporter putSurfaceList(List<Surface> surfaceList,
694 ind().putRawText("<surfaceGroup ");
695 putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
696 sp().putRawText(">").ln();
699 for(Surface surface : surfaceList){
704 ind().putRawText("</surfaceGroup>").ln(2);
711 * @param surface サーフェイス
713 * @throws IOException 出力エラー
715 private XmlExporter putSurface(Surface surface)
717 ind().putRawText("<surface ");
719 Vertex vertex1 = surface.getVertex1();
720 Vertex vertex2 = surface.getVertex2();
721 Vertex vertex3 = surface.getVertex3();
723 putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).sp();
724 putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).sp();
725 putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).sp();
727 putRawText("/>").ln();
733 * @param model モデルデータ
735 * @throws IOException 出力エラー
737 private XmlExporter putVertexList(PmdModel model)
739 ind().putRawText("<vertexList>").ln();
742 boolean dumped = false;
743 List<Vertex> vertexList = model.getVertexList();
744 for(Vertex vertex : vertexList){
751 ind().putRawText("</vertexList>").ln(2);
760 * @throws IOException 出力エラー
762 private XmlExporter putVertex(Vertex vertex)
765 if(vertex.getEdgeAppearance()) bool = "true";
768 ind().putRawText("<vertex ");
769 putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).sp();
770 putAttr("showEdge", bool);
771 sp().putRawText(">").ln();
774 MkPos3D position = vertex.getPosition();
775 ind().putPosition(position).ln();
777 MkVec3D normal = vertex.getNormal();
778 ind().putRawText("<normal ");
779 putFloatAttr("x", (float) normal.getXVal()).sp();
780 putFloatAttr("y", (float) normal.getYVal()).sp();
781 putFloatAttr("z", (float) normal.getZVal()).sp();
782 putRawText("/>").ln();
784 MkPos2D uvPos = vertex.getUVPosition();
785 ind().putRawText("<uvMap ");
786 putFloatAttr("u", (float) uvPos.getXpos()).sp();
787 putFloatAttr("v", (float) uvPos.getYpos()).sp();
788 putRawText("/>").ln();
790 BoneInfo boneA = vertex.getBoneA();
791 BoneInfo boneB = vertex.getBoneB();
792 int weight = vertex.getWeightA();
793 ind().putRawText("<skinning ");
794 putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).sp();
795 putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).sp();
796 putIntAttr("weightBalance", weight).sp();
797 putRawText("/>").ln();
800 ind().putRawText("</vertex>").ln(2);
807 * @param model モデルデータ
809 * @throws IOException 出力エラー
811 private XmlExporter putBoneList(PmdModel model)
813 ind().putRawText("<boneList>").ln();
816 boolean dumped = false;
817 for(BoneInfo bone : model.getBoneList()){
819 ln().putBlockComment(BONETYPE_COMMENT).ln();
826 ind().putRawText("</boneList>").ln(2);
835 * @throws IOException 出力エラー
837 private XmlExporter putBone(BoneInfo bone)
839 I18nText i18nName = bone.getBoneName();
840 BoneType type = bone.getBoneType();
842 StringBuilder boneComment = new StringBuilder();
843 String boneName = i18nName.getText();
844 if(boneName.isEmpty()){
845 boneName = "[NAMELESS]";
847 boneComment.append(boneName);
848 String typeName = type.getGuiName(DEF_LOCALE);
849 boneComment.append(" [").append(typeName).append(']');
850 ind().putLineComment(boneComment.toString()).ln();
852 ind().putRawText("<bone ");
853 putPrimaryNameAttr("name", i18nName).sp();
854 putNumberedIdAttr("boneId", PFX_BONE, bone).sp();
855 putAttr("type", type.name());
856 sp().putRawText(">").ln();
859 putI18nName(i18nName);
861 MkPos3D position = bone.getPosition();
862 ind().putPosition(position).ln();
864 BoneInfo srcBone = bone.getSrcBone();
865 if(bone.getBoneType() == BoneType.LINKEDROT){
866 ind().putRawText("<rotationRatio ");
867 putIntAttr("ratio", bone.getRotationRatio());
868 putRawText(" />").ln();
869 }else if(srcBone != null){
871 switch(getXmlFileType()){
876 iktag = "<sourceBone ";
880 throw new AssertionError();
882 ind().putRawText(iktag);
883 putNumberedIdAttr("boneIdRef", PFX_BONE, srcBone);
885 String ikBoneName = "Ref:" + srcBone.getBoneName().getText();
886 putLineComment(ikBoneName);
890 BoneInfo prev = bone.getPrevBone();
891 BoneInfo next = bone.getNextBone();
893 StringBuilder chainComment = new StringBuilder();
895 chainComment.append('[')
896 .append(prev.getBoneName().getPrimaryText())
901 if(chainComment.length() <= 0) chainComment.append("#");
902 chainComment.append(">> ")
904 .append(next.getBoneName().getPrimaryText())
907 if(chainComment.length() > 0){
909 ind().putLineComment(chainComment).ln();
912 ind().putRawText("<boneChain");
915 putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
919 putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
921 putRawText(" />").ln();
924 ind().putRawText("</bone>").ln(2);
931 * @param model モデルデータ
933 * @throws IOException 出力エラー
935 private XmlExporter putBoneGroupList(PmdModel model)
937 ind().putRawText("<boneGroupList>").ln();
940 boolean dumped = false;
941 List<BoneGroup> groupList = model.getBoneGroupList();
942 for(BoneGroup group : groupList){
943 if(group.isDefaultBoneGroup()) continue;
950 ind().putRawText("</boneGroupList>").ln(2);
957 * @param group ボーングループ情報
959 * @throws IOException 出力エラー
961 private XmlExporter putBoneGroup(BoneGroup group)
963 I18nText i18nName = group.getGroupName();
965 putLocalNameComment(i18nName).ln();
966 ind().putRawText("<boneGroup ");
967 putPrimaryNameAttr("name", i18nName);
968 sp().putRawText(">").ln();
971 putI18nName(i18nName);
973 for(BoneInfo bone : group){
974 ind().putRawText("<boneGroupMember ");
975 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
977 String boneName = "Ref:" + bone.getBoneName().getText();
978 putLineComment(boneName).ln();
982 ind().putRawText("</boneGroup>").ln(2);
989 * @param model モデルデータ
991 * @throws IOException 出力エラー
993 private XmlExporter putIKChainList(PmdModel model)
995 ind().putRawText("<ikChainList>").ln();
998 boolean dumped = false;
999 List<IKChain> chainList = model.getIKChainList();
1000 for(IKChain chain : chainList){
1001 if( ! dumped ) ln();
1007 ind().putRawText("</ikChainList>").ln(2);
1014 * @param chain チェーン情報
1016 * @throws IOException 出力エラー
1018 private XmlExporter putIKChain(IKChain chain)
1020 int depth = chain.getIKDepth();
1021 float weight = chain.getIKWeight();
1022 BoneInfo ikBone = chain.getIkBone();
1024 ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln();
1025 ind().putRawText("<ikChain ");
1026 putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).sp();
1027 putIntAttr("recursiveDepth", depth).sp();
1028 putFloatAttr("weight", weight);
1029 sp().putRawText(">").ln();
1032 for(BoneInfo bone : chain){
1033 ind().putRawText("<chainOrder ");
1034 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
1036 putLineComment("Ref:" + bone.getBoneName().getText());
1041 ind().putRawText("</ikChain>").ln(2);
1048 * @param model モデルデータ
1050 * @throws IOException 出力エラー
1052 private XmlExporter putMorphList(PmdModel model)
1054 ind().putRawText("<morphList>").ln();
1057 boolean dumped = false;
1058 Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
1059 for(MorphType type : MorphType.values()){
1060 if(type == MorphType.BASE) continue;
1061 List<MorphPart> partList = morphMap.get(type);
1062 if(partList == null) continue;
1063 for(MorphPart part : partList){
1065 ln().putBlockComment(MORPHTYPE_COMMENT).ln();
1073 ind().putRawText("</morphList>").ln(2);
1082 * @throws IOException 出力エラー
1084 private XmlExporter putMorphPart(MorphPart part)
1086 I18nText i18nName = part.getMorphName();
1087 String primary = i18nName.getPrimaryText();
1089 putLocalNameComment(i18nName).ln();
1090 ind().putRawText("<morph ");
1091 putAttr("name", primary).sp();
1092 putAttr("type", part.getMorphType().name());
1093 sp().putRawText(">");
1097 putI18nName(i18nName);
1099 for(MorphVertex mvertex : part){
1100 MkPos3D offset = mvertex.getOffset();
1101 Vertex base = mvertex.getBaseVertex();
1103 ind().putRawText("<morphVertex ");
1104 putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).sp();
1105 putFloatAttr("xOff", (float) offset.getXpos()).sp();
1106 putFloatAttr("yOff", (float) offset.getYpos()).sp();
1107 putFloatAttr("zOff", (float) offset.getZpos()).sp();
1113 ind().putRawText("</morph>").ln(2);
1120 * @param model モデルデータ
1122 * @throws IOException 出力エラー
1124 private XmlExporter putRigidList(PmdModel model)
1126 ind().putRawText("<rigidList>").ln();
1129 boolean dumped = false;
1130 for(RigidInfo rigid : model.getRigidList()){
1132 ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
1139 ind().putRawText("</rigidList>").ln(2);
1148 * @throws IOException 出力エラー
1150 private XmlExporter putRigid(RigidInfo rigid)
1152 BoneInfo linkedBone = rigid.getLinkedBone();
1153 I18nText i18nName = rigid.getRigidName();
1154 String primary = i18nName.getPrimaryText();
1156 putLocalNameComment(i18nName).ln();
1157 ind().putRawText("<rigid ");
1158 putAttr("name", primary).sp();
1159 putNumberedIdAttr("rigidId", PFX_RIGID, rigid).sp();
1160 putAttr("behavior", rigid.getBehaviorType().name());
1161 sp().putRawText(">").ln();
1164 putI18nName(i18nName);
1166 if(linkedBone != null){
1167 ind().putRawText("<linkedBone ");
1168 putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
1170 putLineComment("Ref:" + linkedBone.getBoneName().getText());
1174 RigidShape shape = rigid.getRigidShape();
1175 putRigidShape(shape);
1177 MkPos3D position = rigid.getPosition();
1178 ind().putPosition(position).ln();
1180 Rad3d rotation = rigid.getRotation();
1181 ind().putRadRotation(rotation).ln();
1183 DynamicsInfo dynamics = rigid.getDynamicsInfo();
1184 putDynamics(dynamics).ln();
1186 for(RigidGroup group : rigid.getThroughGroupColl()){
1187 ind().putRawText("<throughRigidGroup ");
1188 putNumberedIdAttr("rigidGroupIdRef",
1190 group.getSerialNumber() + 1).sp();
1191 putRawText(" />").ln();
1195 ind().putRawText("</rigid>").ln(2);
1204 * @throws IOException 出力エラー
1206 private XmlExporter putRigidShape(RigidShape shape)
1208 RigidShapeType type = shape.getShapeType();
1212 ind().putRawText("<rigidShapeBox ");
1213 putFloatAttr("width", shape.getWidth()).sp();
1214 putFloatAttr("height", shape.getHeight()).sp();
1215 putFloatAttr("depth", shape.getDepth()).sp();
1218 ind().putRawText("<rigidShapeSphere ");
1219 putFloatAttr("radius", shape.getRadius()).sp();
1222 ind().putRawText("<rigidShapeCapsule ");
1223 putFloatAttr("height", shape.getHeight()).sp();
1224 putFloatAttr("radius", shape.getRadius()).sp();
1228 throw new AssertionError();
1231 putRawText("/>").ln();
1238 * @param dynamics 力学設定
1240 * @throws IOException 出力エラー
1242 private XmlExporter putDynamics(DynamicsInfo dynamics)
1244 ind().putRawText("<dynamics").ln();
1246 ind().putFloatAttr("mass", dynamics.getMass()).ln();
1247 ind().putFloatAttr("dampingPosition",
1248 dynamics.getDampingPosition()).ln();
1249 ind().putFloatAttr("dampingRotation",
1250 dynamics.getDampingRotation()).ln();
1251 ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
1252 ind().putFloatAttr("friction", dynamics.getFriction()).ln();
1254 ind().putRawText("/>").ln();
1261 * @param model モデルデータ
1263 * @throws IOException 出力エラー
1265 private XmlExporter putRigidGroupList(PmdModel model)
1267 ind().putRawText("<rigidGroupList>").ln(2);
1270 boolean singleLast = false;
1271 for(RigidGroup group : model.getRigidGroupList()){
1272 List<RigidInfo> rigidList = group.getRigidList();
1273 if(singleLast && ! rigidList.isEmpty()){
1276 ind().putRawText("<rigidGroup ");
1277 putNumberedIdAttr("rigidGroupId",
1279 group.getSerialNumber() + 1);
1280 if(rigidList.isEmpty()){
1281 putRawText(" />").ln();
1285 putRawText(" >").ln();
1288 for(RigidInfo rigid : rigidList){
1289 ind().putRawText("<rigidGroupMember ");
1290 putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).sp();
1293 putLineComment("Ref:" + rigid.getRigidName().getText());
1298 ind().putRawText("</rigidGroup>").ln(2);
1307 ind().putRawText("</rigidGroupList>").ln(2);
1314 * @param model モデルデータ
1316 * @throws IOException 出力エラー
1318 private XmlExporter putJointList(PmdModel model)
1320 ind().putRawText("<jointList>").ln();
1323 boolean dumped = false;
1324 List<JointInfo> jointList = model.getJointList();
1325 for(JointInfo joint : jointList){
1326 if( ! dumped ) ln();
1332 ind().putRawText("</jointList>").ln(2);
1339 * @param joint ジョイント情報
1341 * @throws IOException 出力エラー
1343 private XmlExporter putJoint(JointInfo joint)
1345 I18nText i18nName = joint.getJointName();
1347 putLocalNameComment(i18nName).ln();
1348 ind().putRawText("<joint ");
1349 putPrimaryNameAttr("name", i18nName);
1350 sp().putRawText(">").ln();
1353 putI18nName(i18nName);
1355 RigidInfo rigidA = joint.getRigidA();
1356 RigidInfo rigidB = joint.getRigidB();
1359 putLineComment("[" + rigidA.getRigidName().getText() + "]"
1360 + " <=> [" + rigidB.getRigidName().getText() + "]");
1363 ind().putRawText("<jointedRigidPair ");
1364 putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).sp();
1365 putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).sp();
1366 putRawText("/>").ln(2);
1368 MkPos3D position = joint.getPosition();
1369 ind().putPosition(position).ln();
1371 TripletRange posRange = joint.getPositionRange();
1372 ind().putRawText("<limitPosition").ln();
1375 putFloatAttr("xFrom", posRange.getXFrom()).sp();
1376 putFloatAttr("xTo", posRange.getXTo()).ln();
1378 putFloatAttr("yFrom", posRange.getYFrom()).sp();
1379 putFloatAttr("yTo", posRange.getYTo()).ln();
1381 putFloatAttr("zFrom", posRange.getZFrom()).sp();
1382 putFloatAttr("zTo", posRange.getZTo()).ln();
1384 ind().putRawText("/>").ln(2);
1386 Rad3d rotation = joint.getRotation();
1387 ind().putRadRotation(rotation).ln();
1388 TripletRange rotRange = joint.getRotationRange();
1389 ind().putRawText("<limitRotation").ln();
1392 putFloatAttr("xFrom", rotRange.getXFrom()).sp();
1393 putFloatAttr("xTo", rotRange.getXTo()).ln();
1395 putFloatAttr("yFrom", rotRange.getYFrom()).sp();
1396 putFloatAttr("yTo", rotRange.getYTo()).ln();
1398 putFloatAttr("zFrom", rotRange.getZFrom()).sp();
1399 putFloatAttr("zTo", rotRange.getZTo()).ln();
1401 ind().putRawText("/>").ln(2);
1403 MkPos3D elaPosition = joint.getElasticPosition();
1404 ind().putRawText("<elasticPosition ");
1405 putFloatAttr("x", (float) elaPosition.getXpos()).sp();
1406 putFloatAttr("y", (float) elaPosition.getYpos()).sp();
1407 putFloatAttr("z", (float) elaPosition.getZpos()).sp();
1408 putRawText("/>").ln();
1410 Deg3d elaRotation = joint.getElasticRotation();
1411 ind().putRawText("<elasticRotation ");
1412 putFloatAttr("xDeg", elaRotation.getXDeg()).sp();
1413 putFloatAttr("yDeg", elaRotation.getYDeg()).sp();
1414 putFloatAttr("zDeg", elaRotation.getZDeg()).sp();
1415 putRawText("/>").ln(2);
1418 ind().putRawText("</joint>").ln(2);