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 TOP_COMMENT =
\r
51 " MikuMikuDance\n model-data(*.pmd) on XML";
\r
52 private static final String SCHEMA_LOCATION =
\r
53 PmdXmlResources.NS_PMDXML + " " + PmdXmlResources.SCHEMA_PMDXML;
\r
56 private static final String CR = "\r"; // 0x0d
\r
58 private static final String LF = "\n"; // 0x0a
\r
60 private static final String CRLF = CR + LF; // 0x0d, 0x0a
\r
62 private static final String PFX_SURFACEGROUP = "sg";
\r
63 private static final String PFX_TOONFILE = "tf";
\r
64 private static final String PFX_VERTEX = "vtx";
\r
65 private static final String PFX_BONE = "bn";
\r
66 private static final String PFX_RIGID = "rd";
\r
67 private static final String PFX_RIGIDGROUP = "rg";
\r
69 private static final String BONETYPE_COMMENT =
\r
71 + "[0 : ROTATE : Rotate : 回転 :]\n"
\r
72 + "[1 : ROTMOV : Rotate/Move : 回転/移動 :]\n"
\r
73 + "[2 : IK : IK : IK :]\n"
\r
74 + "[3 : UNKNOWN : Unknown : 不明 :]\n"
\r
75 + "[4 : UNDERIK : Under IK : IK影響下(回転) :]\n"
\r
76 + "[5 : UNDERROT : Under rotate : 回転影響下 :]\n"
\r
77 + "[6 : IKCONNECTED : IK connected : IK接続先 :]\n"
\r
78 + "[7 : HIDDEN : Hidden : 非表示 :]\n"
\r
79 + "[8 : TWIST : Twist : 捩り :]\n"
\r
80 + "[9 : LINKEDROT : Linked Rotate: 回転連動 :]\n";
\r
82 private static final String MORPHTYPE_COMMENT =
\r
84 + "[1 : EYEBROW : まゆ ]\n"
\r
85 + "[2 : EYE : 目 ]\n"
\r
86 + "[3 : LIP : リップ ]\n"
\r
87 + "[4 : EXTRA : その他 ]\n";
\r
89 private static final String RIGIDBEHAVIOR_COMMENT =
\r
90 "Rigid behavior types:\n"
\r
91 + "[0 : FOLLOWBONE : ボーン追従 ]\n"
\r
92 + "[1 : ONLYDYNAMICS : 物理演算 ]\n"
\r
93 + "[2 : BONEDDYNAMICS : ボーン位置合わせ ]\n";
\r
95 private String generator = "";
\r
99 * 文字エンコーディングはUTF-8が用いられる。
\r
100 * @param stream 出力ストリーム
\r
102 public PmdXmlExporter(OutputStream stream){
\r
108 * Generatorメタ情報を設定する。
\r
109 * @param generatorArg Generatorメタ情報
\r
110 * @throws NullPointerException 引数がnull
\r
112 public void setGenerator(String generatorArg)
\r
113 throws NullPointerException{
\r
114 if(generatorArg == null) throw new NullPointerException();
\r
115 this.generator = generatorArg;
\r
120 * 任意の文字列がBasicLatin文字のみから構成されるか判定する。
\r
122 * @return null、長さ0もしくはBasicLatin文字のみから構成されるならtrue
\r
124 public static boolean hasOnlyBasicLatin(CharSequence seq){
\r
125 if(seq == null) return true;
\r
126 int length = seq.length();
\r
127 for(int pos = 0; pos < length; pos++){
\r
128 char ch = seq.charAt(pos);
\r
129 if(ch > 0x007f) return false;
\r
136 * @return {@inheritDoc}
\r
137 * @throws IOException {@inheritDoc}
\r
140 public PmdXmlExporter ind() throws IOException{
\r
146 * 文字参照によるエスケープを補佐するためのコメントを出力する。
\r
149 * @throws IOException 出力エラー
\r
151 protected PmdXmlExporter putUnescapedComment(CharSequence seq)
\r
152 throws IOException{
\r
153 if( ! isBasicLatinOnlyOut() ) return this;
\r
154 if(hasOnlyBasicLatin(seq)) return this;
\r
155 put(' ').putLineComment(seq);
\r
160 * 多言語化された各種識別名を出力する。
\r
162 * @param text 多言語文字列
\r
164 * @throws IOException 出力エラー
\r
166 protected PmdXmlExporter putI18nName(I18nText text) throws IOException{
\r
167 for(String lang639 : text.lang639CodeList()){
\r
168 if(lang639.equals(I18nText.CODE639_PRIMARY)) continue;
\r
169 String name = text.getText(lang639);
\r
170 ind().put("<i18nName ");
\r
171 putAttr("lang", lang639).put(' ');
\r
172 putAttr("name", name);
\r
174 putUnescapedComment(name);
\r
181 * 番号付けされたID(IDREF)属性を出力する。
\r
182 * @param attrName 属性名
\r
183 * @param prefix IDプレフィクス
\r
186 * @throws IOException 出力エラー
\r
188 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
\r
189 CharSequence prefix,
\r
191 throws IOException{
\r
192 put(attrName).put("=\"");
\r
193 put(prefix).put(num);
\r
199 * 番号付けされたID(IDREF)属性を出力する。
\r
200 * @param attrName 属性名
\r
201 * @param prefix IDプレフィクス
\r
202 * @param numbered 番号付けされたオブジェクト
\r
204 * @throws IOException 出力エラー
\r
206 protected PmdXmlExporter putNumberedIdAttr(CharSequence attrName,
\r
207 CharSequence prefix,
\r
208 SerialNumbered numbered )
\r
209 throws IOException{
\r
210 putNumberedIdAttr(attrName, prefix, numbered.getSerialNumber());
\r
216 * @param position 位置情報
\r
218 * @throws IOException 出力エラー
\r
220 protected PmdXmlExporter putPosition(Pos3d position) throws IOException{
\r
222 putFloatAttr("x", position.getXPos()).put(' ');
\r
223 putFloatAttr("y", position.getYPos()).put(' ');
\r
224 putFloatAttr("z", position.getZPos()).put(' ');
\r
231 * @param rotation 姿勢情報
\r
233 * @throws IOException 出力エラー
\r
235 protected PmdXmlExporter putRadRotation(Rad3d rotation)
\r
236 throws IOException{
\r
237 put("<radRotation ");
\r
238 putFloatAttr("xRad", rotation.getXRad()).put(' ');
\r
239 putFloatAttr("yRad", rotation.getYRad()).put(' ');
\r
240 putFloatAttr("zRad", rotation.getZRad()).put(' ');
\r
246 * 多言語識別名属性のローカルな名前をコメント出力する。
\r
247 * @param name 多言語識別名
\r
249 * @throws IOException 出力エラー
\r
251 protected PmdXmlExporter putLocalNameComment(I18nText name)
\r
252 throws IOException{
\r
253 String localName = name.getText();
\r
254 ind().putLineComment(localName);
\r
259 * 多言語識別名属性のプライマリな名前を出力する。
\r
260 * @param attrName 属性名
\r
261 * @param name 多言語識別名
\r
263 * @throws IOException 出力エラー
\r
265 protected PmdXmlExporter putPrimaryNameAttr(CharSequence attrName,
\r
267 throws IOException{
\r
268 String primaryName = name.getPrimaryText();
\r
269 putAttr(attrName, primaryName);
\r
274 * PMDモデルデータをXML形式で出力する。
\r
275 * @param model PMDモデルデータ
\r
276 * @throws IOException 出力エラー
\r
278 public void putPmdModel(PmdModel model) throws IOException{
\r
279 ind().put("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>").ln(2);
\r
281 ind().putBlockComment(TOP_COMMENT).ln(2);
\r
284 ind().put("<!DOCTYPE pmdModel").ln();
\r
285 ind().put(" SYSTEM \"")
\r
286 .put(PmdXmlResources.DTD_PMDXML)
\r
291 I18nText modelName = model.getModelName();
\r
292 ind().putLocalNameComment(modelName).ln();
\r
293 ind().put("<pmdModel").ln();
\r
295 ind().putAttr("xmlns", PmdXmlResources.NS_PMDXML).ln();
\r
296 ind().putAttr("xmlns:xsi", XmlResourceResolver.NS_XSD).ln();
\r
297 ind().putAttr("xsi:schemaLocation", SCHEMA_LOCATION).ln();
\r
298 ind().putAttr("schemaVersion", PmdXmlResources.VER_PMDXML).ln(2);
\r
299 ind().putPrimaryNameAttr("name", modelName).ln();
\r
303 putModelInfo(model).flush();
\r
304 putMetaInfo(model).flush();
\r
305 putMaterialList(model).flush();
\r
306 putToonMap(model).flush();
\r
307 putBoneList(model).flush();
\r
308 putBoneGroupList(model).flush();
\r
309 putIKChainList(model).flush();
\r
310 putMorphList(model).flush();
\r
311 putRigidList(model).flush();
\r
312 putRigidGroupList(model).flush();
\r
313 putJointList(model).flush();
\r
314 putSurfaceGroupList(model).flush();
\r
315 putVertexList(model).flush();
\r
317 ind().put("</pmdModel>").ln(2);
\r
318 ind().put("<!-- EOF -->").ln();
\r
325 * @param model モデル情報
\r
327 * @throws IOException 出力エラー
\r
329 private PmdXmlExporter putModelInfo(PmdModel model)
\r
330 throws IOException{
\r
331 I18nText modelName = model.getModelName();
\r
332 putI18nName(modelName);
\r
335 I18nText description = model.getDescription();
\r
336 for(String lang639 : description.lang639CodeList()){
\r
337 String descText = description.getText(lang639);
\r
338 putDescription(lang639, descText);
\r
347 * @param lang639 言語コード
\r
348 * @param content 詳細内容
\r
350 * @throws IOException 出力エラー
\r
352 private PmdXmlExporter putDescription(CharSequence lang639,
\r
353 CharSequence content)
\r
354 throws IOException{
\r
355 String text = content.toString();
\r
356 text = text.replace(CRLF, LF);
\r
357 text = text.replace(CR, LF);
\r
359 ind().put("<description");
\r
360 if( ! I18nText.CODE639_PRIMARY.equals(lang639) ){
\r
362 putAttr("lang", lang639);
\r
366 putBRedContent(text);
\r
369 ind().put("</description>").ln();
\r
371 if( ! hasOnlyBasicLatin(text) && isBasicLatinOnlyOut() ){
\r
372 putBlockComment(text);
\r
379 * break要素を含む要素内容を出力する。
\r
380 * 必要に応じてXML定義済み実体文字が割り振られた文字、
\r
381 * コントロールコード、および非BasicLatin文字がエスケープされる。
\r
383 * @param content 内容
\r
385 * @throws IOException 出力エラー
\r
387 protected BasicXmlExporter putBRedContent(CharSequence content)
\r
388 throws IOException{
\r
389 int length = content.length();
\r
391 for(int pos = 0; pos < length; pos++){
\r
392 char ch = content.charAt(pos);
\r
395 }else if(Character.isISOControl(ch)){
\r
396 putCharRef2Hex(ch);
\r
397 }else if( ! isBasicLatin(ch) && isBasicLatinOnlyOut()){
\r
398 putCharRef4Hex(ch);
\r
401 case '&': put("&"); break;
\r
402 case '<': put("<"); break;
\r
403 case '>': put(">"); break;
\r
404 case '"': put("""); break;
\r
405 case '\'': put("'"); break;
\r
406 default: put(ch); break;
\r
416 * @param model モデルデータ
\r
418 * @throws IOException 出力エラー
\r
420 private PmdXmlExporter putMetaInfo(PmdModel model) throws IOException{
\r
421 ind().put("<license>").ln();
\r
422 ind().put("</license>").ln(2);
\r
424 ind().put("<credits>").ln();
\r
425 ind().put("</credits>").ln(2);
\r
427 ind().put("<meta ");
\r
428 putAttr("name", "generator").put(' ')
\r
429 .putAttr("content", this.generator);
\r
431 ind().put("<meta ");
\r
432 putAttr("name", "siteURL").put(' ').putAttr("content", "");
\r
434 ind().put("<meta ");
\r
435 putAttr("name", "imageURL").put(' ').putAttr("content", "");
\r
443 * @param model モデルデータ
\r
445 * @throws IOException 出力エラー
\r
447 private PmdXmlExporter putMaterialList(PmdModel model)
\r
448 throws IOException{
\r
449 ind().put("<materialList>").ln(2);
\r
453 for(Material material : model.getMaterialList()){
\r
454 putMaterial(material, ct++);
\r
458 ind().put("</materialList>").ln(2);
\r
465 * @param material マテリアル素材
\r
466 * @param no マテリアル通し番号
\r
468 * @throws IOException 出力エラー
\r
470 private PmdXmlExporter putMaterial(Material material, int no)
\r
471 throws IOException{
\r
473 if(material.getEdgeAppearance()) bool = "true";
\r
474 else bool = "false";
\r
475 I18nText name = material.getMaterialName();
\r
476 String primary = name.getPrimaryText();
\r
477 String local = name.getText();
\r
479 if(local != null && local.length() > 0){
\r
480 ind().putLineComment(local).ln();
\r
482 ind().put("<material ");
\r
483 if(primary != null && primary.length() > 0){
\r
484 putAttr("name", primary).put(' ');
\r
487 putAttr("showEdge", bool);
\r
489 putNumberedIdAttr("surfaceGroupIdRef", PFX_SURFACEGROUP, no);
\r
495 float[] rgba = new float[4];
\r
497 Color diffuse = material.getDiffuseColor();
\r
498 diffuse.getRGBComponents(rgba);
\r
499 ind().put("<diffuse ");
\r
500 putFloatAttr("r", rgba[0]).put(' ');
\r
501 putFloatAttr("g", rgba[1]).put(' ');
\r
502 putFloatAttr("b", rgba[2]).put(' ');
\r
503 putFloatAttr("alpha", rgba[3]).put(' ');
\r
506 Color specular = material.getSpecularColor();
\r
507 specular.getRGBComponents(rgba);
\r
508 float shininess = material.getShininess();
\r
509 ind().put("<specular ");
\r
510 putFloatAttr("r", rgba[0]).put(' ');
\r
511 putFloatAttr("g", rgba[1]).put(' ');
\r
512 putFloatAttr("b", rgba[2]).put(' ');
\r
513 putFloatAttr("shininess", shininess).put(' ');
\r
516 Color ambient = material.getAmbientColor();
\r
517 ambient.getRGBComponents(rgba);
\r
518 ind().put("<ambient ");
\r
519 putFloatAttr("r", rgba[0]).put(' ');
\r
520 putFloatAttr("g", rgba[1]).put(' ');
\r
521 putFloatAttr("b", rgba[2]).put(' ');
\r
524 ShadeInfo shade = material.getShadeInfo();
\r
525 String textureFileName = shade.getTextureFileName();
\r
526 String spheremapFileName = shade.getSpheremapFileName();
\r
528 if(shade.isValidToonIndex()){
\r
529 ind().put("<toon ");
\r
530 int toonIdx = shade.getToonIndex();
\r
531 putNumberedIdAttr("toonFileIdRef", PFX_TOONFILE, toonIdx);
\r
533 String toonFileName = shade.getToonFileName();
\r
534 if(toonFileName != null && toonFileName.length() > 0){
\r
535 put(' ').putLineComment(toonFileName);
\r
540 if(textureFileName != null && textureFileName.length() > 0){
\r
541 ind().put("<textureFile ");
\r
542 putAttr("winFileName", textureFileName);
\r
546 if(spheremapFileName != null && spheremapFileName.length() > 0){
\r
547 ind().put("<spheremapFile ");
\r
548 putAttr("winFileName", spheremapFileName);
\r
553 ind().put("</material>").ln(2);
\r
559 * トゥーンファイルマッピング情報を出力する。
\r
560 * @param model モデルデータ
\r
562 * @throws IOException 出力エラー
\r
564 private PmdXmlExporter putToonMap(PmdModel model)
\r
565 throws IOException{
\r
566 ind().put("<toonMap>").ln();
\r
569 ToonMap map = model.getToonMap();
\r
570 for(int index = 0; index <= 9; index++){
\r
571 ind().putToon(map, index).ln();
\r
575 ind().put("</toonMap>").ln(2);
\r
580 * 個別のトゥーンファイル情報を出力する。
\r
581 * @param map トゥーンマップ
\r
582 * @param index インデックス値
\r
584 * @throws IOException 出力エラー
\r
586 private PmdXmlExporter putToon(ToonMap map, int index)
\r
587 throws IOException{
\r
589 putNumberedIdAttr("toonFileId", PFX_TOONFILE, index).put(' ');
\r
590 putIntAttr("index", index).put(' ');
\r
591 String toonFile = map.getIndexedToon(index);
\r
592 putAttr("winFileName", toonFile);
\r
594 putUnescapedComment(toonFile);
\r
599 * サーフェイスグループリストを出力する。
\r
600 * @param model モデルデータ
\r
602 * @throws IOException 出力エラー
\r
604 private PmdXmlExporter putSurfaceGroupList(PmdModel model)
\r
605 throws IOException{
\r
606 ind().put("<surfaceGroupList>").ln(2);
\r
610 for(Material material : model.getMaterialList()){
\r
611 List<Surface> surfaceList = material.getSurfaceList();
\r
612 putSurfaceList(surfaceList, ct++);
\r
616 ind().put("</surfaceGroupList>").ln(2);
\r
622 * 個別のサーフェイスグループを出力する。
\r
623 * @param surfaceList サーフェイスのリスト
\r
624 * @param index グループインデックス
\r
626 * @throws IOException 出力エラー
\r
628 private PmdXmlExporter putSurfaceList(List<Surface> surfaceList,
\r
630 throws IOException{
\r
631 ind().put("<surfaceGroup ");
\r
632 putNumberedIdAttr("surfaceGroupId", PFX_SURFACEGROUP, index);
\r
636 for(Surface surface : surfaceList){
\r
637 putSurface(surface);
\r
641 ind().put("</surfaceGroup>").ln(2);
\r
648 * @param surface サーフェイス
\r
650 * @throws IOException 出力エラー
\r
652 private PmdXmlExporter putSurface(Surface surface)
\r
653 throws IOException{
\r
654 ind().put("<surface ");
\r
656 Vertex vertex1 = surface.getVertex1();
\r
657 Vertex vertex2 = surface.getVertex2();
\r
658 Vertex vertex3 = surface.getVertex3();
\r
660 putNumberedIdAttr("vtxIdRef1", PFX_VERTEX, vertex1).put(' ');
\r
661 putNumberedIdAttr("vtxIdRef2", PFX_VERTEX, vertex2).put(' ');
\r
662 putNumberedIdAttr("vtxIdRef3", PFX_VERTEX, vertex3).put(' ');
\r
670 * @param model モデルデータ
\r
672 * @throws IOException 出力エラー
\r
674 private PmdXmlExporter putVertexList(PmdModel model)
\r
675 throws IOException{
\r
676 ind().put("<vertexList>").ln(2);
\r
679 for(Vertex vertex : model.getVertexList()){
\r
684 ind().put("</vertexList>").ln(2);
\r
693 * @throws IOException 出力エラー
\r
695 private PmdXmlExporter putVertex(Vertex vertex)
\r
696 throws IOException{
\r
698 if(vertex.getEdgeAppearance()) bool = "true";
\r
699 else bool = "false";
\r
701 ind().put("<vertex ");
\r
702 putNumberedIdAttr("vtxId", PFX_VERTEX, vertex).put(' ');
\r
703 putAttr("showEdge", bool);
\r
707 Pos3d position = vertex.getPosition();
\r
708 ind().putPosition(position).ln();
\r
710 Vec3d normal = vertex.getNormal();
\r
711 ind().put("<normal ");
\r
712 putFloatAttr("x", normal.getXVal()).put(' ');
\r
713 putFloatAttr("y", normal.getYVal()).put(' ');
\r
714 putFloatAttr("z", normal.getZVal()).put(' ');
\r
717 Pos2d uvPos = vertex.getUVPosition();
\r
718 ind().put("<uvMap ");
\r
719 putFloatAttr("u", uvPos.getXPos()).put(' ');
\r
720 putFloatAttr("v", uvPos.getYPos()).put(' ');
\r
723 BoneInfo boneA = vertex.getBoneA();
\r
724 BoneInfo boneB = vertex.getBoneB();
\r
725 int weight = vertex.getWeightA();
\r
726 ind().put("<skinning ");
\r
727 putNumberedIdAttr("boneIdRef1", PFX_BONE, boneA).put(' ');
\r
728 putNumberedIdAttr("boneIdRef2", PFX_BONE, boneB).put(' ');
\r
729 putIntAttr("weightBalance", weight).put(' ');
\r
733 ind().put("</vertex>").ln(2);
\r
740 * @param model モデルデータ
\r
742 * @throws IOException 出力エラー
\r
744 private PmdXmlExporter putBoneList(PmdModel model)
\r
745 throws IOException{
\r
746 ind().put("<boneList>").ln(2);
\r
749 putBlockComment(BONETYPE_COMMENT).ln();
\r
751 for(BoneInfo bone : model.getBoneList()){
\r
756 ind().put("</boneList>").ln(2);
\r
763 * @param bone ボーン情報
\r
765 * @throws IOException 出力エラー
\r
767 private PmdXmlExporter putBone(BoneInfo bone)
\r
768 throws IOException{
\r
769 I18nText i18nName = bone.getBoneName();
\r
770 BoneType type = bone.getBoneType();
\r
772 putLocalNameComment(i18nName).putLineComment(type.getGuiName()).ln();
\r
773 ind().put("<bone ");
\r
774 putPrimaryNameAttr("name", i18nName).put(' ');
\r
775 putNumberedIdAttr("boneId", PFX_BONE, bone).put(' ');
\r
776 putAttr("type", type.name());
\r
780 putI18nName(i18nName);
\r
782 Pos3d position = bone.getPosition();
\r
783 ind().putPosition(position).ln();
\r
785 BoneInfo ikBone = bone.getIKBone();
\r
786 if(bone.getBoneType() == BoneType.LINKEDROT){
\r
787 ind().put("<rotationRatio ");
\r
788 putIntAttr("ratio", bone.getRotationRatio());
\r
790 }else if(ikBone != null){
\r
791 ind().put("<ikBone ");
\r
792 putNumberedIdAttr("boneIdRef", PFX_BONE, ikBone);
\r
794 String ikBoneName = "Ref:" + ikBone.getBoneName().getText();
\r
795 putLineComment(ikBoneName);
\r
799 StringBuilder chainComment = new StringBuilder();
\r
800 ind().put("<boneChain");
\r
801 BoneInfo prev = bone.getPrevBone();
\r
802 BoneInfo next = bone.getNextBone();
\r
805 putNumberedIdAttr("prevBoneIdRef", PFX_BONE, prev);
\r
806 chainComment.append('[')
\r
807 .append(prev.getBoneName().getPrimaryText())
\r
813 putNumberedIdAttr("nextBoneIdRef", PFX_BONE, next);
\r
814 if(chainComment.length() <= 0) chainComment.append("#");
\r
815 chainComment.append(" =>")
\r
817 .append(next.getBoneName().getPrimaryText())
\r
821 ind().putLineComment(chainComment).ln();
\r
824 ind().put("</bone>").ln(2);
\r
831 * @param model モデルデータ
\r
833 * @throws IOException 出力エラー
\r
835 private PmdXmlExporter putBoneGroupList(PmdModel model)
\r
836 throws IOException{
\r
837 ind().put("<boneGroupList>").ln(2);
\r
840 for(BoneGroup group : model.getBoneGroupList()){
\r
841 if(group.isDefaultBoneGroup()) continue;
\r
842 putBoneGroup(group);
\r
846 ind().put("</boneGroupList>").ln(2);
\r
852 * 個別のボーングループ情報を出力する。
\r
853 * @param group ボーングループ情報
\r
855 * @throws IOException 出力エラー
\r
857 private PmdXmlExporter putBoneGroup(BoneGroup group)
\r
858 throws IOException{
\r
859 I18nText i18nName = group.getGroupName();
\r
861 putLocalNameComment(i18nName).ln();
\r
862 ind().put("<boneGroup ");
\r
863 putPrimaryNameAttr("name", i18nName);
\r
867 putI18nName(i18nName);
\r
869 for(BoneInfo bone : group){
\r
870 ind().put("<boneGroupMember ");
\r
871 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
\r
873 String boneName = "Ref:" + bone.getBoneName().getText();
\r
874 putLineComment(boneName).ln();
\r
878 ind().put("</boneGroup>").ln(2);
\r
885 * @param model モデルデータ
\r
887 * @throws IOException 出力エラー
\r
889 private PmdXmlExporter putIKChainList(PmdModel model)
\r
890 throws IOException{
\r
891 ind().put("<ikChainList>").ln(2);
\r
894 for(IKChain chain : model.getIKChainList()){
\r
899 ind().put("</ikChainList>").ln(2);
\r
905 * 個別のIKチェーン情報を出力する。
\r
906 * @param chain チェーン情報
\r
908 * @throws IOException 出力エラー
\r
910 private PmdXmlExporter putIKChain(IKChain chain)
\r
911 throws IOException{
\r
912 int depth = chain.getIKDepth();
\r
913 float weight = chain.getIKWeight();
\r
914 BoneInfo ikBone = chain.getIkBone();
\r
916 ind().putLineComment("Ref:" + ikBone.getBoneName().getText()).ln();
\r
917 ind().put("<ikChain ");
\r
918 putNumberedIdAttr("ikBoneIdRef", PFX_BONE, ikBone).put(' ');
\r
919 putIntAttr("recursiveDepth", depth).put(' ');
\r
920 putFloatAttr("weight", weight);
\r
924 for(BoneInfo bone : chain){
\r
925 ind().put("<chainOrder ");
\r
926 putNumberedIdAttr("boneIdRef", PFX_BONE, bone);
\r
928 putLineComment("Ref:" + bone.getBoneName().getText());
\r
933 ind().put("</ikChain>").ln(2);
\r
940 * @param model モデルデータ
\r
942 * @throws IOException 出力エラー
\r
944 private PmdXmlExporter putMorphList(PmdModel model)
\r
945 throws IOException{
\r
946 ind().put("<morphList>").ln(2);
\r
949 putBlockComment(MORPHTYPE_COMMENT).ln();
\r
951 Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();
\r
952 for(MorphType type : MorphType.values()){
\r
953 if(type == MorphType.BASE) continue;
\r
954 List<MorphPart> partList = morphMap.get(type);
\r
955 if(partList == null) continue;
\r
956 for(MorphPart part : partList){
\r
957 putMorphPart(part);
\r
962 ind().put("</morphList>").ln(2);
\r
969 * @param part モーフ情報
\r
971 * @throws IOException 出力エラー
\r
973 private PmdXmlExporter putMorphPart(MorphPart part)
\r
974 throws IOException{
\r
975 I18nText i18nName = part.getMorphName();
\r
976 String primary = i18nName.getPrimaryText();
\r
978 ind().put("<morph ");
\r
979 putAttr("name", primary).put(' ');
\r
980 putAttr("type", part.getMorphType().name());
\r
982 putUnescapedComment(primary);
\r
986 putI18nName(i18nName);
\r
988 for(MorphVertex mvertex : part){
\r
989 Pos3d offset = mvertex.getOffset();
\r
990 Vertex base = mvertex.getBaseVertex();
\r
992 ind().put("<morphVertex ");
\r
993 putNumberedIdAttr("vtxIdRef", PFX_VERTEX, base).put(' ');
\r
994 putFloatAttr("xOff", offset.getXPos()).put(' ');
\r
995 putFloatAttr("yOff", offset.getYPos()).put(' ');
\r
996 putFloatAttr("zOff", offset.getZPos()).put(' ');
\r
1002 ind().put("</morph>").ln(2);
\r
1009 * @param model モデルデータ
\r
1011 * @throws IOException 出力エラー
\r
1013 private PmdXmlExporter putRigidList(PmdModel model)
\r
1014 throws IOException{
\r
1015 ind().put("<rigidList>").ln(2);
\r
1018 putBlockComment(RIGIDBEHAVIOR_COMMENT).ln();
\r
1020 for(RigidInfo rigid : model.getRigidList()){
\r
1025 ind().put("</rigidList>").ln(2);
\r
1032 * @param rigid 剛体情報
\r
1034 * @throws IOException 出力エラー
\r
1036 private PmdXmlExporter putRigid(RigidInfo rigid)
\r
1037 throws IOException{
\r
1038 BoneInfo linkedBone = rigid.getLinkedBone();
\r
1039 I18nText i18nName = rigid.getRigidName();
\r
1040 String primary = i18nName.getPrimaryText();
\r
1042 putLocalNameComment(i18nName).ln();
\r
1043 ind().put("<rigid ");
\r
1044 putAttr("name", primary).put(' ');
\r
1045 putNumberedIdAttr("rigidId", PFX_RIGID, rigid).put(' ');
\r
1046 putAttr("behavior", rigid.getBehaviorType().name());
\r
1050 putI18nName(i18nName);
\r
1052 ind().put("<linkedBone ");
\r
1053 putNumberedIdAttr("boneIdRef", PFX_BONE, linkedBone);
\r
1055 putLineComment("Ref:" + linkedBone.getBoneName().getText());
\r
1058 RigidShape shape = rigid.getRigidShape();
\r
1059 putRigidShape(shape);
\r
1061 Pos3d position = rigid.getPosition();
\r
1062 ind().putPosition(position).ln();
\r
1064 Rad3d rotation = rigid.getRotation();
\r
1065 ind().putRadRotation(rotation).ln();
\r
1067 DynamicsInfo dynamics = rigid.getDynamicsInfo();
\r
1068 putDynamics(dynamics).ln();
\r
1070 for(RigidGroup group : rigid.getThroughGroupColl()){
\r
1071 ind().put("<throughRigidGroup ");
\r
1072 putNumberedIdAttr("rigidGroupIdRef",
\r
1074 group.getSerialNumber() + 1).put(' ');
\r
1079 ind().put("</rigid>").ln(2);
\r
1086 * @param shape 剛体形状
\r
1088 * @throws IOException 出力エラー
\r
1090 private PmdXmlExporter putRigidShape(RigidShape shape)
\r
1091 throws IOException{
\r
1092 RigidShapeType type = shape.getShapeType();
\r
1096 ind().put("<rigidShapeBox ");
\r
1097 putFloatAttr("width", shape.getWidth()).put(' ');
\r
1098 putFloatAttr("height", shape.getHeight()).put(' ');
\r
1099 putFloatAttr("depth", shape.getDepth()).put(' ');
\r
1102 ind().put("<rigidShapeSphere ");
\r
1103 putFloatAttr("radius", shape.getRadius()).put(' ');
\r
1106 ind().put("<rigidShapeCapsule ");
\r
1107 putFloatAttr("height", shape.getHeight()).put(' ');
\r
1108 putFloatAttr("radius", shape.getRadius()).put(' ');
\r
1112 throw new AssertionError();
\r
1122 * @param dynamics 力学設定
\r
1124 * @throws IOException 出力エラー
\r
1126 private PmdXmlExporter putDynamics(DynamicsInfo dynamics)
\r
1127 throws IOException{
\r
1128 ind().put("<dynamics").ln();
\r
1130 ind().putFloatAttr("mass", dynamics.getMass()).ln();
\r
1131 ind().putFloatAttr("dampingPosition",
\r
1132 dynamics.getDampingPosition()).ln();
\r
1133 ind().putFloatAttr("dampingRotation",
\r
1134 dynamics.getDampingRotation()).ln();
\r
1135 ind().putFloatAttr("restitution", dynamics.getRestitution()).ln();
\r
1136 ind().putFloatAttr("friction", dynamics.getFriction()).ln();
\r
1138 ind().put("/>").ln();
\r
1145 * @param model モデルデータ
\r
1147 * @throws IOException 出力エラー
\r
1149 private PmdXmlExporter putRigidGroupList(PmdModel model)
\r
1150 throws IOException{
\r
1151 ind().put("<rigidGroupList>").ln(2);
\r
1154 for(RigidGroup group : model.getRigidGroupList()){
\r
1155 ind().put("<rigidGroup ");
\r
1156 putNumberedIdAttr("rigidGroupId",
\r
1158 group.getSerialNumber() + 1);
\r
1159 List<RigidInfo> rigidList = group.getRigidList();
\r
1160 if(rigidList.size() <= 0){
\r
1167 for(RigidInfo rigid : rigidList){
\r
1168 ind().put("<rigidGroupMember ");
\r
1169 putNumberedIdAttr("rigidIdRef", PFX_RIGID, rigid).put(' ');
\r
1172 putLineComment("Ref:" + rigid.getRigidName().getText());
\r
1177 ind().put("</rigidGroup>").ln(2);
\r
1181 ind().put("</rigidGroupList>").ln(2);
\r
1188 * @param model モデルデータ
\r
1190 * @throws IOException 出力エラー
\r
1192 private PmdXmlExporter putJointList(PmdModel model)
\r
1193 throws IOException{
\r
1194 ind().put("<jointList>").ln(2);
\r
1197 for(JointInfo joint : model.getJointList()){
\r
1202 ind().put("</jointList>").ln(2);
\r
1208 * 個別のジョイント情報を出力する。
\r
1209 * @param joint ジョイント情報
\r
1211 * @throws IOException 出力エラー
\r
1213 private PmdXmlExporter putJoint(JointInfo joint)
\r
1214 throws IOException{
\r
1215 I18nText i18nName = joint.getJointName();
\r
1217 putLocalNameComment(i18nName).ln();
\r
1218 ind().put("<joint ");
\r
1219 putPrimaryNameAttr("name", i18nName);
\r
1223 putI18nName(i18nName);
\r
1225 RigidInfo rigidA = joint.getRigidA();
\r
1226 RigidInfo rigidB = joint.getRigidB();
\r
1227 ind().put("<jointedRigidPair ");
\r
1228 putNumberedIdAttr("rigidIdRef1", PFX_RIGID, rigidA).put(' ');
\r
1229 putNumberedIdAttr("rigidIdRef2", PFX_RIGID, rigidB).put(' ');
\r
1232 putLineComment("[" + rigidA.getRigidName().getText() + "]"
\r
1233 + " <=> [" + rigidB.getRigidName().getText() + "]");
\r
1236 Pos3d position = joint.getPosition();
\r
1237 ind().putPosition(position).ln();
\r
1239 TripletRange posRange = joint.getPositionRange();
\r
1240 ind().put("<limitPosition").ln();
\r
1243 putFloatAttr("xFrom", posRange.getXFrom()).put(' ');
\r
1244 putFloatAttr("xTo", posRange.getXTo()).ln();
\r
1246 putFloatAttr("yFrom", posRange.getYFrom()).put(' ');
\r
1247 putFloatAttr("yTo", posRange.getYTo()).ln();
\r
1249 putFloatAttr("zFrom", posRange.getZFrom()).put(' ');
\r
1250 putFloatAttr("zTo", posRange.getZTo()).ln();
\r
1252 ind().put("/>").ln(2);
\r
1254 Rad3d rotation = joint.getRotation();
\r
1255 ind().putRadRotation(rotation).ln();
\r
1256 TripletRange rotRange = joint.getRotationRange();
\r
1257 ind().put("<limitRotation").ln();
\r
1260 putFloatAttr("xFrom", rotRange.getXFrom()).put(' ');
\r
1261 putFloatAttr("xTo", rotRange.getXTo()).ln();
\r
1263 putFloatAttr("yFrom", rotRange.getYFrom()).put(' ');
\r
1264 putFloatAttr("yTo", rotRange.getYTo()).ln();
\r
1266 putFloatAttr("zFrom", rotRange.getZFrom()).put(' ');
\r
1267 putFloatAttr("zTo", rotRange.getZTo()).ln();
\r
1269 ind().put("/>").ln(2);
\r
1271 Pos3d elaPosition = joint.getElasticPosition();
\r
1272 ind().put("<elasticPosition ");
\r
1273 putFloatAttr("x", elaPosition.getXPos()).put(' ');
\r
1274 putFloatAttr("y", elaPosition.getYPos()).put(' ');
\r
1275 putFloatAttr("z", elaPosition.getZPos()).put(' ');
\r
1278 Deg3d elaRotation = joint.getElasticRotation();
\r
1279 ind().put("<elasticRotation ");
\r
1280 putFloatAttr("xDeg", elaRotation.getXDeg()).put(' ');
\r
1281 putFloatAttr("yDeg", elaRotation.getYDeg()).put(' ');
\r
1282 putFloatAttr("zDeg", elaRotation.getZDeg()).put(' ');
\r
1286 ind().put("</joint>").ln(2);
\r