4 * License : The MIT License
\r
5 * Copyright(c) 2010 MikuToga Partners
\r
8 package jp.sourceforge.mikutoga.pmd.xml;
\r
10 import java.awt.Color;
\r
11 import java.io.IOException;
\r
12 import java.io.OutputStream;
\r
13 import java.util.List;
\r
14 import java.util.Map;
\r
15 import jp.sourceforge.mikutoga.corelib.I18nText;
\r
16 import jp.sourceforge.mikutoga.corelib.SerialNumbered;
\r
17 import jp.sourceforge.mikutoga.pmd.BoneGroup;
\r
18 import jp.sourceforge.mikutoga.pmd.BoneInfo;
\r
19 import jp.sourceforge.mikutoga.pmd.BoneType;
\r
20 import jp.sourceforge.mikutoga.pmd.Deg3d;
\r
21 import jp.sourceforge.mikutoga.pmd.DynamicsInfo;
\r
22 import jp.sourceforge.mikutoga.pmd.IKChain;
\r
23 import jp.sourceforge.mikutoga.pmd.JointInfo;
\r
24 import jp.sourceforge.mikutoga.pmd.Material;
\r
25 import jp.sourceforge.mikutoga.pmd.MorphPart;
\r
26 import jp.sourceforge.mikutoga.pmd.MorphType;
\r
27 import jp.sourceforge.mikutoga.pmd.MorphVertex;
\r
28 import jp.sourceforge.mikutoga.pmd.PmdModel;
\r
29 import jp.sourceforge.mikutoga.pmd.Pos2d;
\r
30 import jp.sourceforge.mikutoga.pmd.Pos3d;
\r
31 import jp.sourceforge.mikutoga.pmd.Rad3d;
\r
32 import jp.sourceforge.mikutoga.pmd.RigidGroup;
\r
33 import jp.sourceforge.mikutoga.pmd.RigidInfo;
\r
34 import jp.sourceforge.mikutoga.pmd.RigidShape;
\r
35 import jp.sourceforge.mikutoga.pmd.RigidShapeType;
\r
36 import jp.sourceforge.mikutoga.pmd.ShadeInfo;
\r
37 import jp.sourceforge.mikutoga.pmd.Surface;
\r
38 import jp.sourceforge.mikutoga.pmd.ToonMap;
\r
39 import jp.sourceforge.mikutoga.pmd.TripletRange;
\r
40 import jp.sourceforge.mikutoga.pmd.Vec3d;
\r
41 import jp.sourceforge.mikutoga.pmd.Vertex;
\r
42 import jp.sourceforge.mikutoga.xml.BasicXmlExporter;
\r
43 import jp.sourceforge.mikutoga.xml.XmlResourceResolver;
\r
46 * XML形式でPMDモデルデータを出力する。
\r
48 public class PmdXmlExporter extends BasicXmlExporter{
\r
50 private static final String GENERATOR = "Mikutoga" + " Ver 0.0.1";
\r
51 private static final String TOP_COMMENT =
\r
52 " MikuMikuDance\n model-data(*.pmd) on XML";
\r
53 private static final String SCHEMA_LOCATION =
\r
54 PmdXmlResources.NS_PMDXML + " " + PmdXmlResources.SCHEMA_PMDXML;
\r
57 private static final String CR = "\r"; // 0x0d
\r
59 private static final String LF = "\n"; // 0x0a
\r
61 private static final String CRLF = CR + LF; // 0x0d, 0x0a
\r
63 private static final String PFX_SURFACEGROUP = "sg";
\r
64 private static final String PFX_TOONFILE = "tf";
\r
65 private static final String PFX_VERTEX = "vtx";
\r
66 private static final String PFX_BONE = "bn";
\r
67 private static final String PFX_RIGID = "rd";
\r
68 private static final String PFX_RIGIDGROUP = "rg";
\r
70 private static final String BONETYPE_COMMENT =
\r
72 + "[0 : ROTATE : Rotate : 回転 :]\n"
\r
73 + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n"
\r
74 + "[2 : IK : IK : IK :]\n"
\r
75 + "[3 : UNKNOWN : Unknown : 不明 :]\n"
\r
76 + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n"
\r
77 + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n"
\r
78 + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n"
\r
79 + "[7 : HIDDEN : Hidden : 非表示 :]\n"
\r
80 + "[8 : TWIST : Twist : 捩り :]\n"
\r
81 + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n";
\r
83 private static final String MORPHTYPE_COMMENT =
\r
85 + "[1 : EYEBROW : まゆ ]\n"
\r
86 + "[2 : EYE : 目 ]\n"
\r
87 + "[3 : LIP : リップ ]\n"
\r
88 + "[4 : EXTRA : その他 ]\n";
\r
90 private static final String RIGIDBEHAVIOR_COMMENT =
\r
91 "Rigid behavior types:\n"
\r
92 + "[0 : FOLLOWBONE : ボーン追従 ]\n"
\r
93 + "[1 : ONLYDYNAMICS : 物理演算 ]\n"
\r
94 + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n";
\r
98 * 文字エンコーディングはUTF-8が用いられる。
\r
99 * @param stream 出力ストリーム
\r
101 public PmdXmlExporter(OutputStream stream){
\r
107 * 任意の文字列がBasicLatin文字のみから構成されるか判定する。
\r
109 * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue
\r
111 public static boolean hasOnlyBasicLatin(CharSequence seq){
\r
112 if(seq == null) return true;
\r
113 int length = seq.length();
\r
114 for(int pos = 0; pos < length; pos++){
\r
115 char ch = seq.charAt(pos);
\r
116 if(ch > 0x007f) return false;
\r
123 * @return {@inheritDoc}
\r
124 * @throws IOException {@inheritDoc}
\r
127 public PmdXmlExporter ind() throws IOException{
\r
133 * 文字参照によるエスケープを補佐するためのコメントを出力する。
\r
136 * @throws IOException 出力エラー
\r
138 protected PmdXmlExporter putUnescapedComment(CharSequence seq)
\r
139 throws IOException{
\r
140 if( ! isBasicLatinOnlyOut() ) return this;
\r
141 if(hasOnlyBasicLatin(seq)) return this;
\r
142 put(' ').putLineComment(seq);
\r
147 * 多言語化された各種識別名を出力する。
\r
149 * @param text 多言語文字列
\r
151 * @throws IOException 出力エラー
\r
153 protected PmdXmlExporter putI18nName(I18nText text) throws IOException{
\r
154 for(String lang639 : text.lang639CodeList()){
\r
155 if(lang639.equals(I18nText.CODE639_PRIMARY)) continue;
\r
156 String name = text.getText(lang639);
\r
157 ind().put("<i18nName ");
\r
158 putAttr("lang", lang639).put(' ');
\r
159 putAttr("name", name);
\r
161 putUnescapedComment(name);
\r
168 * 番号付けされたID(IDREF)属性を出力する。
\r
169 * @param attrName 属性名
\r
170 * @param prefix IDプレフィクス
\r
173 * @throws IOException 出力エラー
\r
175 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
\r
176 CharSequence prefix,
\r
178 throws IOException{
\r
179 put(attrName).put("=\"");
\r
180 put(prefix).put(num);
\r
186 * 番号付けされたID(IDREF)属性を出力する。
\r
187 * @param attrName 属性名
\r
188 * @param prefix IDプレフィクス
\r
189 * @param numbered 番号付けされたオブジェクト
\r
191 * @throws IOException 出力エラー
\r
193 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
\r
194 CharSequence prefix,
\r
195 SerialNumbered numbered )
\r
196 throws IOException{
\r
197 putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber());
\r
203 * @param position 位置情報
\r
205 * @throws IOException 出力エラー
\r
207 protected PmdXmlExporter putPosition(Pos3d position) throws IOException{
\r
209 putFloatAttr("x", position.getXPos()).put(' ');
\r
210 putFloatAttr("y", position.getYPos()).put(' ');
\r
211 putFloatAttr("z", position.getZPos()).put(' ');
\r
218 * @param rotation 姿勢情報
\r
220 * @throws IOException 出力エラー
\r
222 protected PmdXmlExporter putRadRotation(Rad3d rotation)
\r
223 throws IOException{
\r
224 put("<radRotation ");
\r
225 putFloatAttr("xRad", rotation.getXRad()).put(' ');
\r
226 putFloatAttr("yRad", rotation.getYRad()).put(' ');
\r
227 putFloatAttr("zRad", rotation.getZRad()).put(' ');
\r
233 * 多言語識別名属性のローカルな名前をコメント出力する。
\r
234 * @param name 多言語識別名
\r
236 * @throws IOException 出力エラー
\r
238 protected PmdXmlExporter putLocalNameComment(I18nText name)
\r
239 throws IOException{
\r
240 String localName = name.getText();
\r
241 ind().putLineComment(localName);
\r
246 * 多言語識別名属性のプライマリな名前を出力する。
\r
247 * @param attrName 属性名
\r
248 * @param name 多言語識別名
\r
250 * @throws IOException 出力エラー
\r
252 protected PmdXmlExporter putPrimaryNameAttr(CharSequence attrName,
\r
254 throws IOException{
\r
255 String primaryName = name.getPrimaryText();
\r
256 putAttr(attrName, primaryName);
\r
261 * PMDモデルデータをXML形式で出力する。
\r
262 * @param model PMDモデルデータ
\r
263 * @throws IOException 出力エラー
\r
265 public void putPmdModel(PmdModel model) throws IOException{
\r
266 ind().put("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>").ln(2);
\r
268 ind().putBlockComment(TOP_COMMENT).ln(2);
\r
270 ind().put("<!DOCTYPE pmdModel").ln();
\r
271 ind().put(" SYSTEM \"")
\r
272 .put(PmdXmlResources.DTD_PMDXML)
\r
276 I18nText modelName = model.getModelName();
\r
277 ind().putLocalNameComment(modelName).ln();
\r
278 ind().put("<pmdModel").ln();
\r
280 ind().putAttr("xmlns", PmdXmlResources.NS_PMDXML).ln();
\r
281 ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
\r
282 ind().putAttr("xsi:schemaLocation", SCHEMA_LOCATION).ln();
\r
283 ind().putAttr("schemaVersion", PmdXmlResources.VER_PMDXML).ln(2);
\r
284 ind().putPrimaryNameAttr("name", modelName).ln();
\r
288 putModelInfo(model).flush();
\r
289 putMetaInfo(model).flush();
\r
290 putMaterialList(model).flush();
\r
291 putToonMap(model).flush();
\r
292 putBoneList(model).flush();
\r
293 putBoneGroupList(model).flush();
\r
294 putIKChainList(model).flush();
\r
295 putMorphList(model).flush();
\r
296 putRigidList(model).flush();
\r
297 putRigidGroupList(model).flush();
\r
298 putJointList(model).flush();
\r
299 putSurfaceGroupList(model).flush();
\r
300 putVertexList(model).flush();
\r
302 ind().put("</pmdModel>").ln(2);
\r
303 ind().put("<!-- EOF -->").ln();
\r
310 * @param model モデル情報
\r
312 * @throws IOException 出力エラー
\r
314 private PmdXmlExporter putModelInfo(PmdModel model)
\r
315 throws IOException{
\r
316 I18nText modelName = model.getModelName();
\r
317 putI18nName(modelName);
\r
320 I18nText description = model.getDescription();
\r
321 for(String lang639 : description.lang639CodeList()){
\r
322 String descText = description.getText(lang639);
\r
323 putDescription(lang639, descText);
\r
332 * @param lang639 言語コード
\r
333 * @param content 詳細内容
\r
335 * @throws IOException 出力エラー
\r
337 private PmdXmlExporter putDescription(CharSequence lang639,
\r
338 CharSequence content)
\r
339 throws IOException{
\r
340 String text = content.toString();
\r
341 text = text.replace(CRLF, LF);
\r
342 text = text.replace(CR, LF);
\r
344 ind().put("<description");
\r
345 if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
\r
347 putAttr("lang", lang639);
\r
351 putBRedContent(text);
\r
354 ind().put("</description>").ln();
\r
356 if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){
\r
357 putBlockComment(text);
\r
364 * break要素を含む要素内容を出力する。
\r
365 * 必要に応じてXML定義済み実体文字が割り振られた文字、
\r
366 * コントロールコード、および非BasicLatin文字がエスケープされる。
\r
368 * @param content 内容
\r
370 * @throws IOException 出力エラー
\r
372 protected BasicXmlExporter putBRedContent(CharSequence content)
\r
373 throws IOException{
\r
374 int length = content.length();
\r
376 for(int pos = 0; pos < length; pos++){
\r
377 char ch = content.charAt(pos);
\r
380 }else if(Character.isISOControl(ch)){
\r
381 putCharRef2Hex(ch);
\r
382 }else if( ! isBasicLatin(ch) && isBasicLatinOnlyOut()){
\r
383 putCharRef4Hex(ch);
\r
386 case '&': put("&"); break;
\r
387 case '<': put("<"); break;
\r
388 case '>': put(">"); break;
\r
389 case '"': put("""); break;
\r
390 case '\'': put("'"); break;
\r
391 default: put(ch); break;
\r
401 * @param model モデルデータ
\r
403 * @throws IOException 出力エラー
\r
405 private PmdXmlExporter putMetaInfo(PmdModel model) throws IOException{
\r
406 ind().put("<license>").ln();
\r
407 ind().put("</license>").ln(2);
\r
409 ind().put("<credits>").ln();
\r
410 ind().put("</credits>").ln(2);
\r
412 ind().put("<meta ");
\r
413 putAttr("name", "generator").put(' ').putAttr("content", GENERATOR);
\r
415 ind().put("<meta ");
\r
416 putAttr("name", "siteURL").put(' ').putAttr("content", "");
\r
418 ind().put("<meta ");
\r
419 putAttr("name", "imageURL").put(' ').putAttr("content", "");
\r
427 * @param model モデルデータ
\r
429 * @throws IOException 出力エラー
\r
431 private PmdXmlExporter putMaterialList(PmdModel model)
\r
432 throws IOException{
\r
433 ind().put("<materialList>").ln(2);
\r
437 for(Material material : model.getMaterialList()){
\r
438 putMaterial(material, ct++);
\r
442 ind().put("</materialList>").ln(2);
\r
449 * @param material マテリアル素材
\r
450 * @param no マテリアル通し番号
\r
452 * @throws IOException 出力エラー
\r
454 private PmdXmlExporter putMaterial(Material material, int no)
\r
455 throws IOException{
\r
457 if(material.getEdgeAppearance()) bool = "true";
\r
458 else bool = "false";
\r
459 I18nText name = material.getMaterialName();
\r
460 String primary = name.getPrimaryText();
\r
461 String local = name.getText();
\r
463 if(local != null && local.length() > 0){
\r
464 ind().putLineComment(local).ln();
\r
466 ind().put("<material ");
\r
467 if(primary != null && primary.length() > 0){
\r
468 putAttr("name", primary).put(' ');
\r
471 putAttr("showEdge", bool);
\r
473 putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no);
\r
479 float[] rgba = new float[4];
\r
481 Color diffuse = material.getDiffuseColor();
\r
482 diffuse.getRGBComponents(rgba);
\r
483 ind().put("<diffuse ");
\r
484 putFloatAttr("r", rgba[0]).put(' ');
\r
485 putFloatAttr("g", rgba[1]).put(' ');
\r
486 putFloatAttr("b", rgba[2]).put(' ');
\r
487 putFloatAttr("alpha", rgba[3]).put(' ');
\r
490 Color specular = material.getSpecularColor();
\r
491 specular.getRGBComponents(rgba);
\r
492 float shininess = material.getShininess();
\r
493 ind().put("<specular ");
\r
494 putFloatAttr("r", rgba[0]).put(' ');
\r
495 putFloatAttr("g", rgba[1]).put(' ');
\r
496 putFloatAttr("b", rgba[2]).put(' ');
\r
497 putFloatAttr("shininess", shininess).put(' ');
\r
500 Color ambient = material.getAmbientColor();
\r
501 ambient.getRGBComponents(rgba);
\r
502 ind().put("<ambient ");
\r
503 putFloatAttr("r", rgba[0]).put(' ');
\r
504 putFloatAttr("g", rgba[1]).put(' ');
\r
505 putFloatAttr("b", rgba[2]).put(' ');
\r
508 ShadeInfo shade = material.getShadeInfo();
\r
509 String textureFileName = shade.getTextureFileName();
\r
510 String spheremapFileName = shade.getSpheremapFileName();
\r
512 if(shade.isValidToonIndex()){
\r
513 ind().put("<toon ");
\r
514 int toonIdx = shade.getToonIndex();
\r
515 putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
\r
517 String toonFileName = shade.getToonFileName();
\r
518 if(toonFileName != null && toonFileName.length() > 0){
\r
519 put(' ').putLineComment(toonFileName);
\r
524 if(textureFileName != null && textureFileName.length() > 0){
\r
525 ind().put("<textureFile ");
\r
526 putAttr("winFileName", textureFileName);
\r
530 if(spheremapFileName != null && spheremapFileName.length() > 0){
\r
531 ind().put("<spheremapFile ");
\r
532 putAttr("winFileName", spheremapFileName);
\r
537 ind().put("</material>").ln(2);
\r
543 * トゥーンファイルマッピング情報を出力する。
\r
544 * @param model モデルデータ
\r
546 * @throws IOException 出力エラー
\r
548 private PmdXmlExporter putToonMap(PmdModel model)
\r
549 throws IOException{
\r
550 ind().put("<toonMap>").ln();
\r
553 ToonMap map = model.getToonMap();
\r
554 for(int index = 0; index <= 9; index++){
\r
555 ind().putToon(map, index).ln();
\r
559 ind().put("</toonMap>").ln(2);
\r
564 * 個別のトゥーンファイル情報を出力する。
\r
565 * @param map トゥーンマップ
\r
566 * @param index インデックス値
\r
568 * @throws IOException 出力エラー
\r
570 private PmdXmlExporter putToon(ToonMap map, int index)
\r
571 throws IOException{
\r
573 putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).put(' ');
\r
574 putIntAttr("index", index).put(' ');
\r
575 String toonFile = map.getIndexedToon(index);
\r
576 putAttr("winFileName", toonFile);
\r
578 putUnescapedComment(toonFile);
\r
583 * サーフェイスグループリストを出力する。
\r
584 * @param model モデルデータ
\r
586 * @throws IOException 出力エラー
\r
588 private PmdXmlExporter putSurfaceGroupList(PmdModel model)
\r
589 throws IOException{
\r
590 ind().put("<surfaceGroupList>").ln(2);
\r
594 for(Material material : model.getMaterialList()){
\r
595 List<Surface> surfaceList = material.getSurfaceList();
\r
596 putSurfaceList(surfaceList, ct++);
\r
600 ind().put("</surfaceGroupList>").ln(2);
\r
606 * 個別のサーフェイスグループを出力する。
\r
607 * @param surfaceList サーフェイスのリスト
\r
608 * @param index グループインデックス
\r
610 * @throws IOException 出力エラー
\r
612 private PmdXmlExporter putSurfaceList(List<Surface> surfaceList,
\r
614 throws IOException{
\r
615 ind().put("<surfaceGroup ");
\r
616 putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
\r
620 for(Surface surface : surfaceList){
\r
621 putSurface(surface);
\r
625 ind().put("</surfaceGroup>").ln(2);
\r
632 * @param surface サーフェイス
\r
634 * @throws IOException 出力エラー
\r
636 private PmdXmlExporter putSurface(Surface surface)
\r
637 throws IOException{
\r
638 ind().put("<surface ");
\r
640 Vertex vertex1 = surface.getVertex1();
\r
641 Vertex vertex2 = surface.getVertex2();
\r
642 Vertex vertex3 = surface.getVertex3();
\r
644 putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).put(' ');
\r
645 putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).put(' ');
\r
646 putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).put(' ');
\r
654 * @param model モデルデータ
\r
656 * @throws IOException 出力エラー
\r
658 private PmdXmlExporter putVertexList(PmdModel model)
\r
659 throws IOException{
\r
660 ind().put("<vertexList>").ln(2);
\r
663 for(Vertex vertex : model.getVertexList()){
\r
668 ind().put("</vertexList>").ln(2);
\r
677 * @throws IOException 出力エラー
\r
679 private PmdXmlExporter putVertex(Vertex vertex)
\r
680 throws IOException{
\r
682 if(vertex.getEdgeAppearance()) bool = "true";
\r
683 else bool = "false";
\r
685 ind().put("<vertex ");
\r
686 putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).put(' ');
\r
687 putAttr("showEdge", bool);
\r
691 Pos3d position = vertex.getPosition();
\r
692 ind().putPosition(position).ln();
\r
694 Vec3d normal = vertex.getNormal();
\r
695 ind().put("<normal ");
\r
696 putFloatAttr("x", normal.getXVal()).put(' ');
\r
697 putFloatAttr("y", normal.getYVal()).put(' ');
\r
698 putFloatAttr("z", normal.getZVal()).put(' ');
\r
701 Pos2d uvPos = vertex.getUVPosition();
\r
702 ind().put("<uvMap ");
\r
703 putFloatAttr("u", uvPos.getXPos()).put(' ');
\r
704 putFloatAttr("v", uvPos.getYPos()).put(' ');
\r
707 BoneInfo boneA = vertex.getBoneA();
\r
708 BoneInfo boneB = vertex.getBoneB();
\r
709 int weight = vertex.getWeightA();
\r
710 ind().put("<skinning ");
\r
711 putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).put(' ');
\r
712 putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).put(' ');
\r
713 putIntAttr("weightBalance", weight).put(' ');
\r
717 ind().put("</vertex>").ln(2);
\r
724 * @param model モデルデータ
\r
726 * @throws IOException 出力エラー
\r
728 private PmdXmlExporter putBoneList(PmdModel model)
\r
729 throws IOException{
\r
730 ind().put("<boneList>").ln(2);
\r
733 putBlockComment(BONETYPE_COMMENT).ln();
\r
735 for(BoneInfo bone : model.getBoneList()){
\r
740 ind().put("</boneList>").ln(2);
\r
747 * @param bone ボーン情報
\r
749 * @throws IOException 出力エラー
\r
751 private PmdXmlExporter putBone(BoneInfo bone)
\r
752 throws IOException{
\r
753 I18nText i18nName = bone.getBoneName();
\r
754 BoneType type = bone.getBoneType();
\r
756 putLocalNameComment(i18nName).putLineComment(type.getGuiName()).ln();
\r
757 ind().put("<bone ");
\r
758 putPrimaryNameAttr("name", i18nName).put(' ');
\r
759 putNumberedIdAttr("boneId", PFX_BONE, bone).put(' ');
\r
760 putAttr("type", type.name());
\r
764 putI18nName(i18nName);
\r
766 Pos3d position = bone.getPosition();
\r
767 ind().putPosition(position).ln();
\r
769 BoneInfo ikBone = bone.getIKBone();
\r
770 if(bone.getBoneType() == BoneType.LINKEDROT){
\r
771 ind().put("<rotationRatio ");
\r
772 putIntAttr("ratio", bone.getRotationRatio());
\r
774 }else if(ikBone != null){
\r
775 ind().put("<ikBone ");
\r
776 putNumberedIdAttr("boneIdRef", PFX_BONE, ikBone);
\r
778 String ikBoneName = "Ref:" + ikBone.getBoneName().getText();
\r
779 putLineComment(ikBoneName);
\r
783 StringBuilder chainComment = new StringBuilder();
\r
784 ind().put("<boneChain");
\r
785 BoneInfo prev = bone.getPrevBone();
\r
786 BoneInfo next = bone.getNextBone();
\r
789 putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
\r
790 chainComment.append('[')
\r
791 .append(prev.getBoneName().getPrimaryText())
\r
797 putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
\r
798 if(chainComment.length() <= 0) chainComment.append("#");
\r
799 chainComment.append(" =>")
\r
801 .append(next.getBoneName().getPrimaryText())
\r
805 ind().putLineComment(chainComment).ln();
\r
808 ind().put("</bone>").ln(2);
\r
815 * @param model モデルデータ
\r
817 * @throws IOException 出力エラー
\r
819 private PmdXmlExporter putBoneGroupList(PmdModel model)
\r
820 throws IOException{
\r
821 ind().put("<boneGroupList>").ln(2);
\r
824 for(BoneGroup group : model.getBoneGroupList()){
\r
825 if(group.isDefaultBoneGroup()) continue;
\r
826 putBoneGroup(group);
\r
830 ind().put("</boneGroupList>").ln(2);
\r
836 * 個別のボーングループ情報を出力する。
\r
837 * @param group ボーングループ情報
\r
839 * @throws IOException 出力エラー
\r
841 private PmdXmlExporter putBoneGroup(BoneGroup group)
\r
842 throws IOException{
\r
843 I18nText i18nName = group.getGroupName();
\r
845 putLocalNameComment(i18nName).ln();
\r
846 ind().put("<boneGroup ");
\r
847 putPrimaryNameAttr("name", i18nName);
\r
851 putI18nName(i18nName);
\r
853 for(BoneInfo bone : group){
\r
854 ind().put("<boneGroupMember ");
\r
855 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
\r
857 String boneName = "Ref:" + bone.getBoneName().getText();
\r
858 putLineComment(boneName).ln();
\r
862 ind().put("</boneGroup>").ln(2);
\r
869 * @param model モデルデータ
\r
871 * @throws IOException 出力エラー
\r
873 private PmdXmlExporter putIKChainList(PmdModel model)
\r
874 throws IOException{
\r
875 ind().put("<ikChainList>").ln(2);
\r
878 for(IKChain chain : model.getIKChainList()){
\r
883 ind().put("</ikChainList>").ln(2);
\r
889 * 個別のIKチェーン情報を出力する。
\r
890 * @param chain チェーン情報
\r
892 * @throws IOException 出力エラー
\r
894 private PmdXmlExporter putIKChain(IKChain chain)
\r
895 throws IOException{
\r
896 int depth = chain.getIKDepth();
\r
897 float weight = chain.getIKWeight();
\r
898 BoneInfo ikBone = chain.getIkBone();
\r
900 ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln();
\r
901 ind().put("<ikChain ");
\r
902 putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).put(' ');
\r
903 putIntAttr("recursiveDepth", depth).put(' ');
\r
904 putFloatAttr("weight", weight);
\r
908 for(BoneInfo bone : chain){
\r
909 ind().put("<chainOrder ");
\r
910 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
\r
912 putLineComment("Ref:" + bone.getBoneName().getText());
\r
917 ind().put("</ikChain>").ln(2);
\r
924 * @param model モデルデータ
\r
926 * @throws IOException 出力エラー
\r
928 private PmdXmlExporter putMorphList(PmdModel model)
\r
929 throws IOException{
\r
930 ind().put("<morphList>").ln(2);
\r
933 putBlockComment(MORPHTYPE_COMMENT).ln();
\r
935 Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
\r
936 for(MorphType type : MorphType.values()){
\r
937 if(type == MorphType.BASE) continue;
\r
938 List<MorphPart> partList = morphMap.get(type);
\r
939 if(partList == null) continue;
\r
940 for(MorphPart part : partList){
\r
941 putMorphPart(part);
\r
946 ind().put("</morphList>").ln(2);
\r
953 * @param part モーフ情報
\r
955 * @throws IOException 出力エラー
\r
957 private PmdXmlExporter putMorphPart(MorphPart part)
\r
958 throws IOException{
\r
959 I18nText i18nName = part.getMorphName();
\r
960 String primary = i18nName.getPrimaryText();
\r
962 ind().put("<morph ");
\r
963 putAttr("name", primary).put(' ');
\r
964 putAttr("type", part.getMorphType().name());
\r
966 putUnescapedComment(primary);
\r
970 putI18nName(i18nName);
\r
972 for(MorphVertex mvertex : part){
\r
973 Pos3d offset = mvertex.getOffset();
\r
974 Vertex base = mvertex.getBaseVertex();
\r
976 ind().put("<morphVertex ");
\r
977 putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).put(' ');
\r
978 putFloatAttr("xOff", offset.getXPos()).put(' ');
\r
979 putFloatAttr("yOff", offset.getYPos()).put(' ');
\r
980 putFloatAttr("zOff", offset.getZPos()).put(' ');
\r
986 ind().put("</morph>").ln(2);
\r
993 * @param model モデルデータ
\r
995 * @throws IOException 出力エラー
\r
997 private PmdXmlExporter putRigidList(PmdModel model)
\r
998 throws IOException{
\r
999 ind().put("<rigidList>").ln(2);
\r
1002 putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
\r
1004 for(RigidInfo rigid : model.getRigidList()){
\r
1009 ind().put("</rigidList>").ln(2);
\r
1016 * @param rigid 剛体情報
\r
1018 * @throws IOException 出力エラー
\r
1020 private PmdXmlExporter putRigid(RigidInfo rigid)
\r
1021 throws IOException{
\r
1022 BoneInfo linkedBone = rigid.getLinkedBone();
\r
1023 I18nText i18nName = rigid.getRigidName();
\r
1024 String primary = i18nName.getPrimaryText();
\r
1026 putLocalNameComment(i18nName).ln();
\r
1027 ind().put("<rigid ");
\r
1028 putAttr("name", primary).put(' ');
\r
1029 putNumberedIdAttr("rigidId", PFX_RIGID, rigid).put(' ');
\r
1030 putAttr("behavior", rigid.getBehaviorType().name());
\r
1034 putI18nName(i18nName);
\r
1036 ind().put("<linkedBone ");
\r
1037 putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
\r
1039 putLineComment("Ref:" + linkedBone.getBoneName().getText());
\r
1042 RigidShape shape = rigid.getRigidShape();
\r
1043 putRigidShape(shape);
\r
1045 Pos3d position = rigid.getPosition();
\r
1046 ind().putPosition(position).ln();
\r
1048 Rad3d rotation = rigid.getRotation();
\r
1049 ind().putRadRotation(rotation).ln();
\r
1051 DynamicsInfo dynamics = rigid.getDynamicsInfo();
\r
1052 putDynamics(dynamics).ln();
\r
1054 for(RigidGroup group : rigid.getThroughGroupColl()){
\r
1055 ind().put("<throughRigidGroup ");
\r
1056 putNumberedIdAttr("rigidGroupIdRef",
\r
1058 group.getSerialNumber() + 1).put(' ');
\r
1063 ind().put("</rigid>").ln(2);
\r
1070 * @param shape 剛体形状
\r
1072 * @throws IOException 出力エラー
\r
1074 private PmdXmlExporter putRigidShape(RigidShape shape)
\r
1075 throws IOException{
\r
1076 RigidShapeType type = shape.getShapeType();
\r
1080 ind().put("<rigidShapeBox ");
\r
1081 putFloatAttr("width", shape.getWidth()).put(' ');
\r
1082 putFloatAttr("height", shape.getHeight()).put(' ');
\r
1083 putFloatAttr("depth", shape.getDepth()).put(' ');
\r
1086 ind().put("<rigidShapeSphere ");
\r
1087 putFloatAttr("radius", shape.getRadius()).put(' ');
\r
1090 ind().put("<rigidShapeCapsule ");
\r
1091 putFloatAttr("height", shape.getHeight()).put(' ');
\r
1092 putFloatAttr("radius", shape.getRadius()).put(' ');
\r
1096 throw new AssertionError();
\r
1106 * @param dynamics 力学設定
\r
1108 * @throws IOException 出力エラー
\r
1110 private PmdXmlExporter putDynamics(DynamicsInfo dynamics)
\r
1111 throws IOException{
\r
1112 ind().put("<dynamics").ln();
\r
1114 ind().putFloatAttr("mass", dynamics.getMass()).ln();
\r
1115 ind().putFloatAttr("dampingPosition",
\r
1116 dynamics.getDampingPosition()).ln();
\r
1117 ind().putFloatAttr("dampingRotation",
\r
1118 dynamics.getDampingRotation()).ln();
\r
1119 ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
\r
1120 ind().putFloatAttr("friction", dynamics.getFriction()).ln();
\r
1122 ind().put("/>").ln();
\r
1129 * @param model モデルデータ
\r
1131 * @throws IOException 出力エラー
\r
1133 private PmdXmlExporter putRigidGroupList(PmdModel model)
\r
1134 throws IOException{
\r
1135 ind().put("<rigidGroupList>").ln(2);
\r
1138 for(RigidGroup group : model.getRigidGroupList()){
\r
1139 ind().put("<rigidGroup ");
\r
1140 putNumberedIdAttr("rigidGroupId",
\r
1142 group.getSerialNumber() + 1);
\r
1143 List<RigidInfo> rigidList = group.getRigidList();
\r
1144 if(rigidList.size() <= 0){
\r
1151 for(RigidInfo rigid : rigidList){
\r
1152 ind().put("<rigidGroupMember ");
\r
1153 putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).put(' ');
\r
1156 putLineComment("Ref:" + rigid.getRigidName().getText());
\r
1161 ind().put("</rigidGroup>").ln(2);
\r
1165 ind().put("</rigidGroupList>").ln(2);
\r
1172 * @param model モデルデータ
\r
1174 * @throws IOException 出力エラー
\r
1176 private PmdXmlExporter putJointList(PmdModel model)
\r
1177 throws IOException{
\r
1178 ind().put("<jointList>").ln(2);
\r
1181 for(JointInfo joint : model.getJointList()){
\r
1186 ind().put("</jointList>").ln(2);
\r
1192 * 個別のジョイント情報を出力する。
\r
1193 * @param joint ジョイント情報
\r
1195 * @throws IOException 出力エラー
\r
1197 private PmdXmlExporter putJoint(JointInfo joint)
\r
1198 throws IOException{
\r
1199 I18nText i18nName = joint.getJointName();
\r
1201 putLocalNameComment(i18nName).ln();
\r
1202 ind().put("<joint ");
\r
1203 putPrimaryNameAttr("name", i18nName);
\r
1207 putI18nName(i18nName);
\r
1209 RigidInfo rigidA = joint.getRigidA();
\r
1210 RigidInfo rigidB = joint.getRigidB();
\r
1211 ind().put("<jointedRigidPair ");
\r
1212 putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).put(' ');
\r
1213 putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).put(' ');
\r
1216 putLineComment("[" + rigidA.getRigidName().getText() + "]"
\r
1217 + " <=> [" + rigidB.getRigidName().getText() + "]");
\r
1220 Pos3d position = joint.getPosition();
\r
1221 ind().putPosition(position).ln();
\r
1223 TripletRange posRange = joint.getPositionRange();
\r
1224 ind().put("<limitPosition").ln();
\r
1227 putFloatAttr("xFrom", posRange.getXFrom()).put(' ');
\r
1228 putFloatAttr("xTo", posRange.getXTo()).ln();
\r
1230 putFloatAttr("yFrom", posRange.getYFrom()).put(' ');
\r
1231 putFloatAttr("yTo", posRange.getYTo()).ln();
\r
1233 putFloatAttr("zFrom", posRange.getZFrom()).put(' ');
\r
1234 putFloatAttr("zTo", posRange.getZTo()).ln();
\r
1236 ind().put("/>").ln(2);
\r
1238 Rad3d rotation = joint.getRotation();
\r
1239 ind().putRadRotation(rotation).ln();
\r
1240 TripletRange rotRange = joint.getRotationRange();
\r
1241 ind().put("<limitRotation").ln();
\r
1244 putFloatAttr("xFrom", rotRange.getXFrom()).put(' ');
\r
1245 putFloatAttr("xTo", rotRange.getXTo()).ln();
\r
1247 putFloatAttr("yFrom", rotRange.getYFrom()).put(' ');
\r
1248 putFloatAttr("yTo", rotRange.getYTo()).ln();
\r
1250 putFloatAttr("zFrom", rotRange.getZFrom()).put(' ');
\r
1251 putFloatAttr("zTo", rotRange.getZTo()).ln();
\r
1253 ind().put("/>").ln(2);
\r
1255 Pos3d elaPosition = joint.getElasticPosition();
\r
1256 ind().put("<elasticPosition ");
\r
1257 putFloatAttr("x", elaPosition.getXPos()).put(' ');
\r
1258 putFloatAttr("y", elaPosition.getYPos()).put(' ');
\r
1259 putFloatAttr("z", elaPosition.getZPos()).put(' ');
\r
1262 Deg3d elaRotation = joint.getElasticRotation();
\r
1263 ind().put("<elasticRotation ");
\r
1264 putFloatAttr("xDeg", elaRotation.getXDeg()).put(' ');
\r
1265 putFloatAttr("yDeg", elaRotation.getYDeg()).put(' ');
\r
1266 putFloatAttr("zDeg", elaRotation.getZDeg()).put(' ');
\r
1270 ind().put("</joint>").ln(2);
\r