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.util.List;
13 import java.util.Locale;
15 import jp.sfjp.mikutoga.corelib.I18nText;
16 import jp.sfjp.mikutoga.math.MkPos2D;
17 import jp.sfjp.mikutoga.math.MkPos3D;
18 import jp.sfjp.mikutoga.math.MkVec3D;
19 import jp.sfjp.mikutoga.pmd.BoneType;
20 import jp.sfjp.mikutoga.pmd.Deg3d;
21 import jp.sfjp.mikutoga.pmd.MorphType;
22 import jp.sfjp.mikutoga.pmd.Rad3d;
23 import jp.sfjp.mikutoga.pmd.RigidShapeType;
24 import jp.sfjp.mikutoga.pmd.TripletRange;
25 import jp.sfjp.mikutoga.pmd.model.BoneGroup;
26 import jp.sfjp.mikutoga.pmd.model.BoneInfo;
27 import jp.sfjp.mikutoga.pmd.model.DynamicsInfo;
28 import jp.sfjp.mikutoga.pmd.model.IKChain;
29 import jp.sfjp.mikutoga.pmd.model.JointInfo;
30 import jp.sfjp.mikutoga.pmd.model.Material;
31 import jp.sfjp.mikutoga.pmd.model.MorphPart;
32 import jp.sfjp.mikutoga.pmd.model.MorphVertex;
33 import jp.sfjp.mikutoga.pmd.model.PmdModel;
34 import jp.sfjp.mikutoga.pmd.model.RigidGroup;
35 import jp.sfjp.mikutoga.pmd.model.RigidInfo;
36 import jp.sfjp.mikutoga.pmd.model.RigidShape;
37 import jp.sfjp.mikutoga.pmd.model.SerialNumbered;
38 import jp.sfjp.mikutoga.pmd.model.ShadeInfo;
39 import jp.sfjp.mikutoga.pmd.model.Surface;
40 import jp.sfjp.mikutoga.pmd.model.ToonMap;
41 import jp.sfjp.mikutoga.pmd.model.Vertex;
42 import jp.sourceforge.mikutoga.xml.BasicXmlExporter;
43 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
46 * 101009形式XMLでPMDモデルデータを出力する。
48 public class PmdXmlExporter 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 static final Locale DEF_LOCALE = Locale.JAPANESE;
97 private String generator = null;
99 private XmlModelFileType xmlType = XmlModelFileType.XML_101009;
105 public PmdXmlExporter(){
115 public XmlModelFileType getXmlFileType(){
123 public void setXmlFileType(XmlModelFileType type){
130 this.xmlType = XmlModelFileType.XML_130128;
133 throw new IllegalArgumentException();
136 assert this.xmlType == XmlModelFileType.XML_101009
137 || this.xmlType == XmlModelFileType.XML_130128;
143 * Generatorメタ情報を設定する。
144 * @param generatorArg Generatorメタ情報。表示したくないときはnull
146 public void setGenerator(String generatorArg){
147 this.generator = generatorArg;
152 * 任意の文字列がBasicLatin文字のみから構成されるか判定する。
154 * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue
156 public static boolean hasOnlyBasicLatin(CharSequence seq){
157 if(seq == null) return true;
158 int length = seq.length();
159 for(int pos = 0; pos < length; pos++){
160 char ch = seq.charAt(pos);
161 if(ch > 0x007f) return false;
168 * @return {@inheritDoc}
169 * @throws IOException {@inheritDoc}
172 public PmdXmlExporter ind() throws IOException{
178 * 文字参照によるエスケープを補佐するためのコメントを出力する。
181 * @throws IOException 出力エラー
183 protected PmdXmlExporter putUnescapedComment(CharSequence seq)
185 if( ! isBasicLatinOnlyOut() ) return this;
186 if(hasOnlyBasicLatin(seq)) return this;
187 sp().putLineComment(seq);
196 * @throws IOException 出力エラー
198 protected PmdXmlExporter putI18nName(I18nText text) throws IOException{
199 for(String lang639 : text.lang639CodeList()){
200 if(lang639.equals(I18nText.CODE639_PRIMARY)) continue;
201 String name = text.getI18nText(lang639);
202 ind().putRawText("<i18nName ");
203 putAttr("lang", lang639).sp();
204 putAttr("name", name);
206 putUnescapedComment(name);
213 * 番号付けされたID(IDREF)属性を出力する。
214 * @param attrName 属性名
215 * @param prefix IDプレフィクス
218 * @throws IOException 出力エラー
220 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
224 putRawText(attrName).putRawText("=\"");
225 putRawText(prefix).putXsdInt(num);
231 * 番号付けされたID(IDREF)属性を出力する。
232 * @param attrName 属性名
233 * @param prefix IDプレフィクス
234 * @param numbered 番号付けされたオブジェクト
236 * @throws IOException 出力エラー
238 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
240 SerialNumbered numbered )
242 putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber());
248 * @param position 位置情報
250 * @throws IOException 出力エラー
252 protected PmdXmlExporter putPosition(MkPos3D position)
254 putRawText("<position ");
255 putFloatAttr("x", (float) position.getXpos()).sp();
256 putFloatAttr("y", (float) position.getYpos()).sp();
257 putFloatAttr("z", (float) position.getZpos()).sp();
264 * @param rotation 姿勢情報
266 * @throws IOException 出力エラー
268 protected PmdXmlExporter putRadRotation(Rad3d rotation)
270 putRawText("<radRotation ");
271 putFloatAttr("xRad", rotation.getXRad()).sp();
272 putFloatAttr("yRad", rotation.getYRad()).sp();
273 putFloatAttr("zRad", rotation.getZRad()).sp();
279 * 多言語識別名属性のローカルな名前をコメント出力する。
282 * @throws IOException 出力エラー
284 protected PmdXmlExporter putLocalNameComment(I18nText name)
286 String localName = name.getText();
287 if(localName.isEmpty()){
288 localName = "[NAMELESS]";
290 ind().putLineComment(localName);
295 * 多言語識別名属性のプライマリな名前を出力する。
296 * @param attrName 属性名
299 * @throws IOException 出力エラー
301 protected PmdXmlExporter putPrimaryNameAttr(CharSequence attrName,
304 String primaryName = name.getPrimaryText();
305 putAttr(attrName, primaryName);
310 * PMDモデルデータをXML形式で出力する。
311 * @param model PMDモデルデータ
312 * @param xmlOut XML出力先
313 * @throws IOException 出力エラー
315 public void putPmdModel(PmdModel model, Appendable xmlOut)
317 setAppendable(xmlOut);
319 ind().putRawText("<?xml")
320 .sp().putAttr("version","1.0")
321 .sp().putAttr("encoding","UTF-8")
322 .sp().putRawText("?>").ln(2);
324 ind().putBlockComment(TOP_COMMENT).ln(2);
326 I18nText modelName = model.getModelName();
327 ind().putLocalNameComment(modelName).ln();
328 ind().putRawText("<pmdModel").ln();
334 if(this.xmlType == XmlModelFileType.XML_101009){
335 defns = Schema101009.NS_PMDXML;
336 xsduri = Schema101009.SCHEMA_PMDXML;
337 version = Schema101009.VER_PMDXML;
338 }else if(this.xmlType == XmlModelFileType.XML_130128){
339 defns = Schema130128.NS_PMDXML;
340 xsduri = Schema130128.SCHEMA_PMDXML;
341 version = Schema130128.VER_PMDXML;
344 throw new AssertionError();
347 ind().putAttr("xmlns", defns).ln();
349 ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
351 ind().putRawText("xsi:schemaLocation").putRawText("=\"");
352 putRawText(defns).ln();
354 ind().putRawText(xsduri).putRawCh('"').ln();
357 ind().putAttr("schemaVersion", version).ln(2);
358 ind().putPrimaryNameAttr("name", modelName).ln();
361 putRawText(">").ln(2);
363 putModelInfo(model).flush();
364 putMetaInfo(model).flush();
365 putMaterialList(model).flush();
366 putToonMap(model).flush();
367 putBoneList(model).flush();
368 putBoneGroupList(model).flush();
369 putIKChainList(model).flush();
370 putMorphList(model).flush();
371 putRigidList(model).flush();
372 putRigidGroupList(model).flush();
373 putJointList(model).flush();
374 putSurfaceGroupList(model).flush();
375 putVertexList(model).flush();
377 ind().putRawText("</pmdModel>").ln(2);
378 ind().putRawText("<!-- EOF -->").ln();
387 * @throws IOException 出力エラー
389 private PmdXmlExporter putModelInfo(PmdModel model)
391 I18nText modelName = model.getModelName();
392 putI18nName(modelName);
395 I18nText description = model.getDescription();
396 for(String lang639 : description.lang639CodeList()){
397 String descText = description.getI18nText(lang639);
398 putDescription(lang639, descText);
407 * @param lang639 言語コード
408 * @param content 詳細内容
410 * @throws IOException 出力エラー
412 private PmdXmlExporter putDescription(CharSequence lang639,
413 CharSequence content)
415 String text = content.toString();
416 text = text.replace(CRLF, LF);
417 text = text.replace(CR, LF);
419 ind().putRawText("<description");
420 if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
421 sp().putAttr("lang", lang639).sp();
423 putRawText(">").ln();
425 putBRedContent(text);
427 ind().putRawText("</description>").ln();
429 if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){
430 putBlockComment(text);
437 * break要素を含む要素内容を出力する。
438 * 必要に応じてXML定義済み実体文字が割り振られた文字、
439 * コントロールコード、および非BasicLatin文字がエスケープされる。
443 * @throws IOException 出力エラー
445 protected BasicXmlExporter putBRedContent(CharSequence content)
447 int length = content.length();
451 for(int idx = 0; idx < length; idx++){
452 char ch = content.charAt(idx);
454 CharSequence seq = content.subSequence(startPos, idx);
455 putContent(seq).putRawText("<br/>").ln();
460 if(startPos < length){
461 CharSequence seq = content.subSequence(startPos, length);
462 putContent(seq).ln();
470 * @param model モデルデータ
472 * @throws IOException 出力エラー
474 private PmdXmlExporter putMetaInfo(PmdModel model) throws IOException{
475 ind().putRawText("<license>").ln();
476 ind().putRawText("</license>").ln(2);
478 ind().putRawText("<credits>").ln();
479 ind().putRawText("</credits>").ln(2);
481 if(this.generator != null){
482 ind().putRawText("<meta ");
483 putAttr("name", "generator").sp()
484 .putAttr("content", this.generator);
485 putRawText(" />").ln();
488 ind().putRawText("<meta ");
489 putAttr("name", "siteURL").sp().putAttr("content", "");
490 putRawText(" />").ln();
491 ind().putRawText("<meta ");
492 putAttr("name", "imageURL").sp().putAttr("content", "");
493 putRawText(" />").ln(2);
500 * @param model モデルデータ
502 * @throws IOException 出力エラー
504 private PmdXmlExporter putMaterialList(PmdModel model)
506 ind().putRawText("<materialList>").ln();
510 boolean dumped = false;
511 List<Material> materialList = model.getMaterialList();
512 for(Material material : materialList){
514 putMaterial(material, ct++);
519 ind().putRawText("</materialList>").ln(2);
526 * @param material マテリアル素材
527 * @param no マテリアル通し番号
529 * @throws IOException 出力エラー
531 private PmdXmlExporter putMaterial(Material material, int no)
534 if(material.getEdgeAppearance()) bool = "true";
536 I18nText name = material.getMaterialName();
537 String primary = name.getPrimaryText();
538 String local = name.getText();
540 if(local != null && local.length() > 0){
541 ind().putLineComment(local).ln();
543 ind().putRawText("<material ");
544 if(primary != null && primary.length() > 0){
545 putAttr("name", primary).sp();
548 putAttr("showEdge", bool);
550 putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no);
551 sp().putRawCh('>').ln();
556 float[] rgba = new float[4];
558 Color diffuse = material.getDiffuseColor();
559 diffuse.getRGBComponents(rgba);
560 ind().putRawText("<diffuse ");
561 putFloatAttr("r", rgba[0]).sp();
562 putFloatAttr("g", rgba[1]).sp();
563 putFloatAttr("b", rgba[2]).sp();
564 putFloatAttr("alpha", rgba[3]).sp();
565 putRawText("/>").ln();
567 Color specular = material.getSpecularColor();
568 specular.getRGBComponents(rgba);
569 float shininess = material.getShininess();
570 ind().putRawText("<specular ");
571 putFloatAttr("r", rgba[0]).sp();
572 putFloatAttr("g", rgba[1]).sp();
573 putFloatAttr("b", rgba[2]).sp();
574 putFloatAttr("shininess", shininess).sp();
575 putRawText("/>").ln();
577 Color ambient = material.getAmbientColor();
578 ambient.getRGBComponents(rgba);
579 ind().putRawText("<ambient ");
580 putFloatAttr("r", rgba[0]).sp();
581 putFloatAttr("g", rgba[1]).sp();
582 putFloatAttr("b", rgba[2]).sp();
583 putRawText("/>").ln();
585 ShadeInfo shade = material.getShadeInfo();
586 String textureFileName = shade.getTextureFileName();
587 String spheremapFileName = shade.getSpheremapFileName();
589 if(shade.isValidToonIndex()){
590 ind().putRawText("<toon ");
591 int toonIdx = shade.getToonIndex();
592 putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
594 String toonFileName = shade.getToonFileName();
595 if(toonFileName != null && toonFileName.length() > 0){
596 sp().putLineComment(toonFileName);
601 if(textureFileName != null && textureFileName.length() > 0){
602 ind().putRawText("<textureFile ");
603 putAttr("winFileName", textureFileName);
604 putRawText(" />").ln();
607 if(spheremapFileName != null && spheremapFileName.length() > 0){
608 ind().putRawText("<spheremapFile ");
609 putAttr("winFileName", spheremapFileName);
610 putRawText(" />").ln();
614 ind().putRawText("</material>").ln(2);
620 * トゥーンファイルマッピング情報を出力する。
621 * @param model モデルデータ
623 * @throws IOException 出力エラー
625 private PmdXmlExporter putToonMap(PmdModel model)
627 ind().putRawText("<toonMap>").ln();
630 ToonMap map = model.getToonMap();
631 for(int index = 0; index <= 9; index++){
632 ind().putToon(map, index).ln();
636 ind().putRawText("</toonMap>").ln(2);
641 * 個別のトゥーンファイル情報を出力する。
643 * @param index インデックス値
645 * @throws IOException 出力エラー
647 private PmdXmlExporter putToon(ToonMap map, int index)
649 putRawText("<toonDef ");
650 putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).sp();
651 putIntAttr("index", index).sp();
652 String toonFile = map.getIndexedToon(index);
653 putAttr("winFileName", toonFile);
655 putUnescapedComment(toonFile);
660 * サーフェイスグループリストを出力する。
661 * @param model モデルデータ
663 * @throws IOException 出力エラー
665 private PmdXmlExporter putSurfaceGroupList(PmdModel model)
667 ind().putRawText("<surfaceGroupList>").ln();
671 boolean dumped = false;
672 List<Material> materialList = model.getMaterialList();
673 for(Material material : materialList){
674 List<Surface> surfaceList = material.getSurfaceList();
676 putSurfaceList(surfaceList, ct++);
681 ind().putRawText("</surfaceGroupList>").ln(2);
687 * 個別のサーフェイスグループを出力する。
688 * @param surfaceList サーフェイスのリスト
689 * @param index グループインデックス
691 * @throws IOException 出力エラー
693 private PmdXmlExporter putSurfaceList(List<Surface> surfaceList,
696 ind().putRawText("<surfaceGroup ");
697 putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
698 sp().putRawText(">").ln();
701 for(Surface surface : surfaceList){
706 ind().putRawText("</surfaceGroup>").ln(2);
713 * @param surface サーフェイス
715 * @throws IOException 出力エラー
717 private PmdXmlExporter putSurface(Surface surface)
719 ind().putRawText("<surface ");
721 Vertex vertex1 = surface.getVertex1();
722 Vertex vertex2 = surface.getVertex2();
723 Vertex vertex3 = surface.getVertex3();
725 putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).sp();
726 putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).sp();
727 putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).sp();
729 putRawText("/>").ln();
735 * @param model モデルデータ
737 * @throws IOException 出力エラー
739 private PmdXmlExporter putVertexList(PmdModel model)
741 ind().putRawText("<vertexList>").ln();
744 boolean dumped = false;
745 List<Vertex> vertexList = model.getVertexList();
746 for(Vertex vertex : vertexList){
753 ind().putRawText("</vertexList>").ln(2);
762 * @throws IOException 出力エラー
764 private PmdXmlExporter putVertex(Vertex vertex)
767 if(vertex.getEdgeAppearance()) bool = "true";
770 ind().putRawText("<vertex ");
771 putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).sp();
772 putAttr("showEdge", bool);
773 sp().putRawText(">").ln();
776 MkPos3D position = vertex.getPosition();
777 ind().putPosition(position).ln();
779 MkVec3D normal = vertex.getNormal();
780 ind().putRawText("<normal ");
781 putFloatAttr("x", (float) normal.getXVal()).sp();
782 putFloatAttr("y", (float) normal.getYVal()).sp();
783 putFloatAttr("z", (float) normal.getZVal()).sp();
784 putRawText("/>").ln();
786 MkPos2D uvPos = vertex.getUVPosition();
787 ind().putRawText("<uvMap ");
788 putFloatAttr("u", (float) uvPos.getXpos()).sp();
789 putFloatAttr("v", (float) uvPos.getYpos()).sp();
790 putRawText("/>").ln();
792 BoneInfo boneA = vertex.getBoneA();
793 BoneInfo boneB = vertex.getBoneB();
794 int weight = vertex.getWeightA();
795 ind().putRawText("<skinning ");
796 putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).sp();
797 putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).sp();
798 putIntAttr("weightBalance", weight).sp();
799 putRawText("/>").ln();
802 ind().putRawText("</vertex>").ln(2);
809 * @param model モデルデータ
811 * @throws IOException 出力エラー
813 private PmdXmlExporter putBoneList(PmdModel model)
815 ind().putRawText("<boneList>").ln();
818 boolean dumped = false;
819 for(BoneInfo bone : model.getBoneList()){
821 ln().putBlockComment(BONETYPE_COMMENT).ln();
828 ind().putRawText("</boneList>").ln(2);
837 * @throws IOException 出力エラー
839 private PmdXmlExporter putBone(BoneInfo bone)
841 I18nText i18nName = bone.getBoneName();
842 BoneType type = bone.getBoneType();
844 StringBuilder boneComment = new StringBuilder();
845 String boneName = i18nName.getText();
846 if(boneName.isEmpty()){
847 boneName = "[NAMELESS]";
849 boneComment.append(boneName);
850 String typeName = type.getGuiName(DEF_LOCALE);
851 boneComment.append(" [").append(typeName).append(']');
852 ind().putLineComment(boneComment.toString()).ln();
854 ind().putRawText("<bone ");
855 putPrimaryNameAttr("name", i18nName).sp();
856 putNumberedIdAttr("boneId", PFX_BONE, bone).sp();
857 putAttr("type", type.name());
858 sp().putRawText(">").ln();
861 putI18nName(i18nName);
863 MkPos3D position = bone.getPosition();
864 ind().putPosition(position).ln();
866 BoneInfo srcBone = bone.getSrcBone();
867 if(bone.getBoneType() == BoneType.LINKEDROT){
868 ind().putRawText("<rotationRatio ");
869 putIntAttr("ratio", bone.getRotationRatio());
870 putRawText(" />").ln();
871 }else if(srcBone != null){
873 switch(getXmlFileType()){
878 iktag = "<sourceBone ";
882 throw new AssertionError();
884 ind().putRawText(iktag);
885 putNumberedIdAttr("boneIdRef", PFX_BONE, srcBone);
887 String ikBoneName = "Ref:" + srcBone.getBoneName().getText();
888 putLineComment(ikBoneName);
892 BoneInfo prev = bone.getPrevBone();
893 BoneInfo next = bone.getNextBone();
895 StringBuilder chainComment = new StringBuilder();
897 chainComment.append('[')
898 .append(prev.getBoneName().getPrimaryText())
903 if(chainComment.length() <= 0) chainComment.append("#");
904 chainComment.append(">> ")
906 .append(next.getBoneName().getPrimaryText())
909 if(chainComment.length() > 0){
911 ind().putLineComment(chainComment).ln();
914 ind().putRawText("<boneChain");
917 putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
921 putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
923 putRawText(" />").ln();
926 ind().putRawText("</bone>").ln(2);
933 * @param model モデルデータ
935 * @throws IOException 出力エラー
937 private PmdXmlExporter putBoneGroupList(PmdModel model)
939 ind().putRawText("<boneGroupList>").ln();
942 boolean dumped = false;
943 List<BoneGroup> groupList = model.getBoneGroupList();
944 for(BoneGroup group : groupList){
945 if(group.isDefaultBoneGroup()) continue;
952 ind().putRawText("</boneGroupList>").ln(2);
959 * @param group ボーングループ情報
961 * @throws IOException 出力エラー
963 private PmdXmlExporter putBoneGroup(BoneGroup group)
965 I18nText i18nName = group.getGroupName();
967 putLocalNameComment(i18nName).ln();
968 ind().putRawText("<boneGroup ");
969 putPrimaryNameAttr("name", i18nName);
970 sp().putRawText(">").ln();
973 putI18nName(i18nName);
975 for(BoneInfo bone : group){
976 ind().putRawText("<boneGroupMember ");
977 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
979 String boneName = "Ref:" + bone.getBoneName().getText();
980 putLineComment(boneName).ln();
984 ind().putRawText("</boneGroup>").ln(2);
991 * @param model モデルデータ
993 * @throws IOException 出力エラー
995 private PmdXmlExporter putIKChainList(PmdModel model)
997 ind().putRawText("<ikChainList>").ln();
1000 boolean dumped = false;
1001 List<IKChain> chainList = model.getIKChainList();
1002 for(IKChain chain : chainList){
1003 if( ! dumped ) ln();
1009 ind().putRawText("</ikChainList>").ln(2);
1016 * @param chain チェーン情報
1018 * @throws IOException 出力エラー
1020 private PmdXmlExporter putIKChain(IKChain chain)
1022 int depth = chain.getIKDepth();
1023 float weight = chain.getIKWeight();
1024 BoneInfo ikBone = chain.getIkBone();
1026 ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln();
1027 ind().putRawText("<ikChain ");
1028 putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).sp();
1029 putIntAttr("recursiveDepth", depth).sp();
1030 putFloatAttr("weight", weight);
1031 sp().putRawText(">").ln();
1034 for(BoneInfo bone : chain){
1035 ind().putRawText("<chainOrder ");
1036 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
1038 putLineComment("Ref:" + bone.getBoneName().getText());
1043 ind().putRawText("</ikChain>").ln(2);
1050 * @param model モデルデータ
1052 * @throws IOException 出力エラー
1054 private PmdXmlExporter putMorphList(PmdModel model)
1056 ind().putRawText("<morphList>").ln();
1059 boolean dumped = false;
1060 Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
1061 for(MorphType type : MorphType.values()){
1062 if(type == MorphType.BASE) continue;
1063 List<MorphPart> partList = morphMap.get(type);
1064 if(partList == null) continue;
1065 for(MorphPart part : partList){
1067 ln().putBlockComment(MORPHTYPE_COMMENT).ln();
1075 ind().putRawText("</morphList>").ln(2);
1084 * @throws IOException 出力エラー
1086 private PmdXmlExporter putMorphPart(MorphPart part)
1088 I18nText i18nName = part.getMorphName();
1089 String primary = i18nName.getPrimaryText();
1091 putLocalNameComment(i18nName).ln();
1092 ind().putRawText("<morph ");
1093 putAttr("name", primary).sp();
1094 putAttr("type", part.getMorphType().name());
1095 sp().putRawText(">");
1099 putI18nName(i18nName);
1101 for(MorphVertex mvertex : part){
1102 MkPos3D offset = mvertex.getOffset();
1103 Vertex base = mvertex.getBaseVertex();
1105 ind().putRawText("<morphVertex ");
1106 putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).sp();
1107 putFloatAttr("xOff", (float) offset.getXpos()).sp();
1108 putFloatAttr("yOff", (float) offset.getYpos()).sp();
1109 putFloatAttr("zOff", (float) offset.getZpos()).sp();
1115 ind().putRawText("</morph>").ln(2);
1122 * @param model モデルデータ
1124 * @throws IOException 出力エラー
1126 private PmdXmlExporter putRigidList(PmdModel model)
1128 ind().putRawText("<rigidList>").ln();
1131 boolean dumped = false;
1132 for(RigidInfo rigid : model.getRigidList()){
1134 ln().putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
1141 ind().putRawText("</rigidList>").ln(2);
1150 * @throws IOException 出力エラー
1152 private PmdXmlExporter putRigid(RigidInfo rigid)
1154 BoneInfo linkedBone = rigid.getLinkedBone();
1155 I18nText i18nName = rigid.getRigidName();
1156 String primary = i18nName.getPrimaryText();
1158 putLocalNameComment(i18nName).ln();
1159 ind().putRawText("<rigid ");
1160 putAttr("name", primary).sp();
1161 putNumberedIdAttr("rigidId", PFX_RIGID, rigid).sp();
1162 putAttr("behavior", rigid.getBehaviorType().name());
1163 sp().putRawText(">").ln();
1166 putI18nName(i18nName);
1168 if(linkedBone != null){
1169 ind().putRawText("<linkedBone ");
1170 putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
1172 putLineComment("Ref:" + linkedBone.getBoneName().getText());
1176 RigidShape shape = rigid.getRigidShape();
1177 putRigidShape(shape);
1179 MkPos3D position = rigid.getPosition();
1180 ind().putPosition(position).ln();
1182 Rad3d rotation = rigid.getRotation();
1183 ind().putRadRotation(rotation).ln();
1185 DynamicsInfo dynamics = rigid.getDynamicsInfo();
1186 putDynamics(dynamics).ln();
1188 for(RigidGroup group : rigid.getThroughGroupColl()){
1189 ind().putRawText("<throughRigidGroup ");
1190 putNumberedIdAttr("rigidGroupIdRef",
1192 group.getSerialNumber() + 1).sp();
1193 putRawText(" />").ln();
1197 ind().putRawText("</rigid>").ln(2);
1206 * @throws IOException 出力エラー
1208 private PmdXmlExporter putRigidShape(RigidShape shape)
1210 RigidShapeType type = shape.getShapeType();
1214 ind().putRawText("<rigidShapeBox ");
1215 putFloatAttr("width", shape.getWidth()).sp();
1216 putFloatAttr("height", shape.getHeight()).sp();
1217 putFloatAttr("depth", shape.getDepth()).sp();
1220 ind().putRawText("<rigidShapeSphere ");
1221 putFloatAttr("radius", shape.getRadius()).sp();
1224 ind().putRawText("<rigidShapeCapsule ");
1225 putFloatAttr("height", shape.getHeight()).sp();
1226 putFloatAttr("radius", shape.getRadius()).sp();
1230 throw new AssertionError();
1233 putRawText("/>").ln();
1240 * @param dynamics 力学設定
1242 * @throws IOException 出力エラー
1244 private PmdXmlExporter putDynamics(DynamicsInfo dynamics)
1246 ind().putRawText("<dynamics").ln();
1248 ind().putFloatAttr("mass", dynamics.getMass()).ln();
1249 ind().putFloatAttr("dampingPosition",
1250 dynamics.getDampingPosition()).ln();
1251 ind().putFloatAttr("dampingRotation",
1252 dynamics.getDampingRotation()).ln();
1253 ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
1254 ind().putFloatAttr("friction", dynamics.getFriction()).ln();
1256 ind().putRawText("/>").ln();
1263 * @param model モデルデータ
1265 * @throws IOException 出力エラー
1267 private PmdXmlExporter putRigidGroupList(PmdModel model)
1269 ind().putRawText("<rigidGroupList>").ln(2);
1272 boolean singleLast = false;
1273 for(RigidGroup group : model.getRigidGroupList()){
1274 List<RigidInfo> rigidList = group.getRigidList();
1275 if(singleLast && ! rigidList.isEmpty()){
1278 ind().putRawText("<rigidGroup ");
1279 putNumberedIdAttr("rigidGroupId",
1281 group.getSerialNumber() + 1);
1282 if(rigidList.isEmpty()){
1283 putRawText(" />").ln();
1287 putRawText(" >").ln();
1290 for(RigidInfo rigid : rigidList){
1291 ind().putRawText("<rigidGroupMember ");
1292 putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).sp();
1295 putLineComment("Ref:" + rigid.getRigidName().getText());
1300 ind().putRawText("</rigidGroup>").ln(2);
1309 ind().putRawText("</rigidGroupList>").ln(2);
1316 * @param model モデルデータ
1318 * @throws IOException 出力エラー
1320 private PmdXmlExporter putJointList(PmdModel model)
1322 ind().putRawText("<jointList>").ln();
1325 boolean dumped = false;
1326 List<JointInfo> jointList = model.getJointList();
1327 for(JointInfo joint : jointList){
1328 if( ! dumped ) ln();
1334 ind().putRawText("</jointList>").ln(2);
1341 * @param joint ジョイント情報
1343 * @throws IOException 出力エラー
1345 private PmdXmlExporter putJoint(JointInfo joint)
1347 I18nText i18nName = joint.getJointName();
1349 putLocalNameComment(i18nName).ln();
1350 ind().putRawText("<joint ");
1351 putPrimaryNameAttr("name", i18nName);
1352 sp().putRawText(">").ln();
1355 putI18nName(i18nName);
1357 RigidInfo rigidA = joint.getRigidA();
1358 RigidInfo rigidB = joint.getRigidB();
1361 putLineComment("[" + rigidA.getRigidName().getText() + "]"
1362 + " <=> [" + rigidB.getRigidName().getText() + "]");
1365 ind().putRawText("<jointedRigidPair ");
1366 putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).sp();
1367 putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).sp();
1368 putRawText("/>").ln(2);
1370 MkPos3D position = joint.getPosition();
1371 ind().putPosition(position).ln();
1373 TripletRange posRange = joint.getPositionRange();
1374 ind().putRawText("<limitPosition").ln();
1377 putFloatAttr("xFrom", posRange.getXFrom()).sp();
1378 putFloatAttr("xTo", posRange.getXTo()).ln();
1380 putFloatAttr("yFrom", posRange.getYFrom()).sp();
1381 putFloatAttr("yTo", posRange.getYTo()).ln();
1383 putFloatAttr("zFrom", posRange.getZFrom()).sp();
1384 putFloatAttr("zTo", posRange.getZTo()).ln();
1386 ind().putRawText("/>").ln(2);
1388 Rad3d rotation = joint.getRotation();
1389 ind().putRadRotation(rotation).ln();
1390 TripletRange rotRange = joint.getRotationRange();
1391 ind().putRawText("<limitRotation").ln();
1394 putFloatAttr("xFrom", rotRange.getXFrom()).sp();
1395 putFloatAttr("xTo", rotRange.getXTo()).ln();
1397 putFloatAttr("yFrom", rotRange.getYFrom()).sp();
1398 putFloatAttr("yTo", rotRange.getYTo()).ln();
1400 putFloatAttr("zFrom", rotRange.getZFrom()).sp();
1401 putFloatAttr("zTo", rotRange.getZTo()).ln();
1403 ind().putRawText("/>").ln(2);
1405 MkPos3D elaPosition = joint.getElasticPosition();
1406 ind().putRawText("<elasticPosition ");
1407 putFloatAttr("x", (float) elaPosition.getXpos()).sp();
1408 putFloatAttr("y", (float) elaPosition.getYpos()).sp();
1409 putFloatAttr("z", (float) elaPosition.getZpos()).sp();
1410 putRawText("/>").ln();
1412 Deg3d elaRotation = joint.getElasticRotation();
1413 ind().putRawText("<elasticRotation ");
1414 putFloatAttr("xDeg", elaRotation.getXDeg()).sp();
1415 putFloatAttr("yDeg", elaRotation.getYDeg()).sp();
1416 putFloatAttr("zDeg", elaRotation.getZDeg()).sp();
1417 putRawText("/>").ln(2);
1420 ind().putRawText("</joint>").ln(2);