OSDN Git Service

1.105.3-SNAPSHOT版開発開始
[mikutoga/TogaGem.git] / src / main / java / jp / sourceforge / mikutoga / pmd / pmdexporter / PmdExporterBase.java
1 /*\r
2  * model exporter for pmd-file\r
3  *\r
4  * License : The MIT License\r
5  * Copyright(c) 2010 MikuToga Partners\r
6  */\r
7 \r
8 package jp.sourceforge.mikutoga.pmd.pmdexporter;\r
9 \r
10 import java.awt.Color;\r
11 import java.io.IOException;\r
12 import java.io.OutputStream;\r
13 import java.util.Collections;\r
14 import java.util.LinkedList;\r
15 import java.util.List;\r
16 import java.util.Map;\r
17 import java.util.Set;\r
18 import jp.sourceforge.mikutoga.corelib.SerialNumbered;\r
19 import jp.sourceforge.mikutoga.parser.pmd.PmdLimits;\r
20 import jp.sourceforge.mikutoga.pmd.BoneGroup;\r
21 import jp.sourceforge.mikutoga.pmd.BoneInfo;\r
22 import jp.sourceforge.mikutoga.pmd.BoneType;\r
23 import jp.sourceforge.mikutoga.pmd.IKChain;\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.ShadeInfo;\r
32 import jp.sourceforge.mikutoga.pmd.Surface;\r
33 import jp.sourceforge.mikutoga.pmd.Vec3d;\r
34 import jp.sourceforge.mikutoga.pmd.Vertex;\r
35 \r
36 /**\r
37  * PMDファイルのエクスポーター(拡張無し基本フォーマット)。\r
38  * <p>\r
39  * 英名対応以降のPMDファイルフォーマットを\r
40  * 使いたくない場合はこのエクスポーターを用いて出力せよ。\r
41  */\r
42 public class PmdExporterBase extends AbstractExporter{\r
43 \r
44     /** 前(親)ボーンが無い場合の便宜的なボーンID。 */\r
45     public static final int NOPREVBONE_ID = 0xffff;\r
46     /** 次(子)ボーンが無い場合の便宜的なボーンID。 */\r
47     public static final int NONEXTBONE_ID = 0x0000;\r
48     /** 影響元IKボーンが無い場合の便宜的なボーンID。 */\r
49     public static final int NOIKBONE_ID = 0x0000;\r
50 \r
51     private static final String MAGIC = "Pmd";\r
52 \r
53     private static final byte[] NULLFILLER =\r
54         { (byte)0x00 };\r
55     private static final byte[] FDFILLER =\r
56         { (byte)0x00, (byte)0xfd };\r
57     private static final byte[] LFFILLER =\r
58         { (byte)0x0a, (byte)0x00, (byte)0xfd };\r
59 \r
60     /** 改行文字列 CR。 */\r
61     private static final String CR = "\r";       // 0x0d\r
62     /** 改行文字列 LF。 */\r
63     private static final String LF = "\n";       // 0x0a\r
64     /** 改行文字列 CRLF。 */\r
65     private static final String CRLF = CR + LF;  // 0x0d, 0x0a\r
66 \r
67     static{\r
68         assert NOPREVBONE_ID > PmdLimits.MAX_BONE - 1;\r
69     }\r
70 \r
71     /**\r
72      * コンストラクタ。\r
73      * @param stream 出力ストリーム\r
74      * @throws NullPointerException 引数がnull\r
75      */\r
76     public PmdExporterBase(OutputStream stream)\r
77             throws NullPointerException{\r
78         super(stream);\r
79         return;\r
80     }\r
81 \r
82     /**\r
83      * 改行文字の正規化を行う。\r
84      * CR(0x0d)およびCRLF(0x0d0a)がLF(0x0a)へと正規化される。\r
85      * @param text 文字列\r
86      * @return 正規化の行われた文字列。\r
87      */\r
88     protected static String normalizeBreak(String text){\r
89         String result = text;\r
90 \r
91         result = result.replace(CRLF, LF);\r
92         result = result.replace(CR, LF);\r
93 \r
94         return result;\r
95     }\r
96 \r
97     /**\r
98      * 文字列を指定されたバイト長で出力する。\r
99      * 文字列の改行記号はLF(0x0a)に正規化される。\r
100      * エンコード結果がバイト長に満たない場合は\r
101      * 1つの0x00及びそれに続く複数の0xfdがパディングされる。\r
102      * @param text 文字列\r
103      * @param maxByteLength バイト長指定\r
104      * @throws IOException 出力エラー\r
105      * @throws IllegalPmdTextException エンコード結果が\r
106      * 指定バイト長をはみ出した。\r
107      */\r
108     protected void dumpText(String text, int maxByteLength)\r
109             throws IOException, IllegalPmdTextException{\r
110         dumpText(text, maxByteLength, FDFILLER);\r
111         return;\r
112     }\r
113 \r
114     /**\r
115      * 文字列を指定されたバイト長で出力する。\r
116      * 文字列の改行記号はLF(0x0a)に正規化される。\r
117      * エンコード結果がバイト長に満たない場合は\r
118      * fillerがパディングされる。\r
119      * @param text 文字列\r
120      * @param maxByteLength バイト超指定\r
121      * @param filler 出力結果が足りない場合の詰め物。\r
122      * それでも足りない場合は最後のbyte要素が繰り返し出力される。\r
123      * @throws IOException 出力エラー\r
124      * @throws IllegalPmdTextException エンコード結果が\r
125      * 指定バイト長をはみ出した\r
126      */\r
127     protected void dumpText(String text, int maxByteLength, byte[] filler)\r
128             throws IOException, IllegalPmdTextException{\r
129         String normalized = normalizeBreak(text);\r
130         int blen = dumpCharSequence(normalized);\r
131         int remain = maxByteLength - blen;\r
132 \r
133         if(remain < 0) throw new IllegalPmdTextException("too long text");\r
134 \r
135         int fillerIdx = 0;\r
136         while(remain > 0){\r
137             if(fillerIdx >= filler.length){\r
138                 fillerIdx = filler.length - 1;\r
139             }\r
140             dumpByte(filler[fillerIdx]);\r
141             fillerIdx++;\r
142             remain--;\r
143         }\r
144 \r
145         return;\r
146     }\r
147 \r
148     /**\r
149      * モデルデータをPMDファイル形式で出力する。\r
150      * @param model モデルデータ\r
151      * @throws IOException 出力エラー\r
152      * @throws IllegalPmdException モデルデータに不備が発見された\r
153      */\r
154     public void dumpPmdModel(PmdModel model)\r
155             throws IOException, IllegalPmdException{\r
156         dumpBasic(model);\r
157         dumpVertexList(model);\r
158         dumpSurfaceList(model);\r
159         dumpMaterialList(model);\r
160         dumpBoneList(model);\r
161         dumpIKChainList(model);\r
162         dumpMorphList(model);\r
163         dumpMorphGroup(model);\r
164         dumpBoneGroupList(model);\r
165 \r
166         return;\r
167     }\r
168 \r
169     /**\r
170      * モデル基本情報を出力する。\r
171      * @param model モデルデータ\r
172      * @throws IOException 出力エラー\r
173      * @throws IllegalPmdTextException モデル名もしくは説明が長すぎる\r
174      */\r
175     private void dumpBasic(PmdModel model)\r
176             throws IOException, IllegalPmdTextException{\r
177         dumpCharSequence(MAGIC);\r
178         float ver = model.getHeaderVersion();\r
179         dumpFloat(ver);\r
180 \r
181         String modelName   = model.getModelName()  .getPrimaryText();\r
182         String description = model.getDescription().getPrimaryText();\r
183 \r
184         dumpText(modelName, PmdLimits.MAXBYTES_MODELNAME);\r
185         dumpText(description, PmdLimits.MAXBYTES_MODELDESC);\r
186 \r
187         flush();\r
188 \r
189         return;\r
190     }\r
191 \r
192     /**\r
193      * 頂点リストを出力する。\r
194      * @param model モデルデータ\r
195      * @throws IOException 出力エラー\r
196      */\r
197     private void dumpVertexList(PmdModel model)\r
198             throws IOException{\r
199         List<Vertex> vList = model.getVertexList();\r
200 \r
201         int vertexNum = vList.size();\r
202         dumpInt(vertexNum);\r
203 \r
204         for(Vertex vertex : vList){\r
205             dumpVertex(vertex);\r
206         }\r
207 \r
208         flush();\r
209 \r
210         return;\r
211     }\r
212 \r
213     /**\r
214      * 個別の頂点データを出力する。\r
215      * @param vertex 頂点\r
216      * @throws IOException 出力エラー\r
217      */\r
218     private void dumpVertex(Vertex vertex)\r
219             throws IOException{\r
220         Pos3d position = vertex.getPosition();\r
221         dumpPos3d(position);\r
222 \r
223         Vec3d normal = vertex.getNormal();\r
224         dumpVec3d(normal);\r
225 \r
226         Pos2d uv = vertex.getUVPosition();\r
227         dumpPos2d(uv);\r
228 \r
229         BoneInfo boneA = vertex.getBoneA();\r
230         BoneInfo boneB = vertex.getBoneB();\r
231         dumpSerialIdAsShort(boneA);\r
232         dumpSerialIdAsShort(boneB);\r
233 \r
234         int weight = vertex.getWeightA();\r
235         dumpByte((byte)weight);\r
236 \r
237         byte edgeFlag;\r
238         boolean hasEdge = vertex.getEdgeAppearance();\r
239         if(hasEdge) edgeFlag = 0x00;\r
240         else        edgeFlag = 0x01;\r
241         dumpByte(edgeFlag);\r
242 \r
243         return;\r
244     }\r
245 \r
246     /**\r
247      * 面リストを出力する。\r
248      * @param model モデルデータ\r
249      * @throws IOException 出力エラー\r
250      */\r
251     private void dumpSurfaceList(PmdModel model)\r
252             throws IOException{\r
253         int surfaceNum = 0;\r
254         List<Material> materialList = model.getMaterialList();\r
255         for(Material material : materialList){\r
256             surfaceNum += material.getSurfaceList().size();\r
257         }\r
258         dumpInt(surfaceNum * 3);\r
259 \r
260         Vertex[] triangle = new Vertex[3];\r
261         for(Material material : materialList){\r
262             for(Surface surface : material){\r
263                 surface.getTriangle(triangle);\r
264                 dumpShort(triangle[0].getSerialNumber());\r
265                 dumpShort(triangle[1].getSerialNumber());\r
266                 dumpShort(triangle[2].getSerialNumber());\r
267             }\r
268         }\r
269 \r
270         flush();\r
271 \r
272         return;\r
273     }\r
274 \r
275     /**\r
276      * マテリアル素材リストを出力する。\r
277      * @param model モデルデータ\r
278      * @throws IOException 出力エラー\r
279      * @throws IllegalPmdTextException シェーディングファイル情報が長すぎる\r
280      */\r
281     private void dumpMaterialList(PmdModel model)\r
282             throws IOException, IllegalPmdTextException{\r
283         List<Material> materialList = model.getMaterialList();\r
284 \r
285         int materialNum = materialList.size();\r
286         dumpInt(materialNum);\r
287 \r
288         float[] rgba = new float[4];\r
289 \r
290         for(Material material : materialList){\r
291             Color diffuse = material.getDiffuseColor();\r
292             diffuse.getRGBComponents(rgba);\r
293             dumpFloat(rgba[0]);\r
294             dumpFloat(rgba[1]);\r
295             dumpFloat(rgba[2]);\r
296             dumpFloat(rgba[3]);\r
297 \r
298             float shininess = material.getShininess();\r
299             dumpFloat(shininess);\r
300 \r
301             Color specular = material.getSpecularColor();\r
302             specular.getRGBComponents(rgba);\r
303             dumpFloat(rgba[0]);\r
304             dumpFloat(rgba[1]);\r
305             dumpFloat(rgba[2]);\r
306 \r
307             Color ambient = material.getAmbientColor();\r
308             ambient.getRGBComponents(rgba);\r
309             dumpFloat(rgba[0]);\r
310             dumpFloat(rgba[1]);\r
311             dumpFloat(rgba[2]);\r
312 \r
313             ShadeInfo shade = material.getShadeInfo();\r
314             int toonIdx = shade.getToonIndex();\r
315             dumpByte(toonIdx);\r
316 \r
317             byte edgeFlag;\r
318             boolean showEdge = material.getEdgeAppearance();\r
319             if(showEdge) edgeFlag = 0x01;\r
320             else         edgeFlag = 0x00;\r
321             dumpByte(edgeFlag);\r
322 \r
323             int surfaceNum = material.getSurfaceList().size();\r
324             dumpInt(surfaceNum * 3);\r
325 \r
326             dumpShadeFileInfo(shade);\r
327         }\r
328 \r
329         flush();\r
330 \r
331         return;\r
332     }\r
333 \r
334     /**\r
335      * シェーディングファイル情報を出力する。\r
336      * @param shade シェーディング情報\r
337      * @throws IOException 出力エラー\r
338      * @throws IllegalPmdTextException ファイル名が長すぎる\r
339      */\r
340     private void dumpShadeFileInfo(ShadeInfo shade)\r
341             throws IOException, IllegalPmdTextException{\r
342         String textureFile   = shade.getTextureFileName();\r
343         String spheremapFile = shade.getSpheremapFileName();\r
344 \r
345         StringBuilder text = new StringBuilder();\r
346         if(textureFile != null) text.append(textureFile);\r
347         if(spheremapFile != null && spheremapFile.length() > 0){\r
348             text.append('*')\r
349                   .append(spheremapFile);\r
350         }\r
351 \r
352         byte[] filler;\r
353         if(text.length() <= 0) filler = NULLFILLER;\r
354         else                   filler = FDFILLER;\r
355 \r
356         dumpText(text.toString(),\r
357                  PmdLimits.MAXBYTES_TEXTUREFILENAME,\r
358                  filler );\r
359 \r
360         return;\r
361     }\r
362 \r
363     /**\r
364      * ボーンリストを出力する。\r
365      * @param model モデルデータ\r
366      * @throws IOException 出力エラー\r
367      * @throws IllegalPmdTextException ボーン名が長すぎる\r
368      */\r
369     private void dumpBoneList(PmdModel model)\r
370             throws IOException, IllegalPmdTextException{\r
371         List<BoneInfo> boneList = model.getBoneList();\r
372 \r
373         int boneNum = boneList.size();\r
374         dumpShort(boneNum);\r
375 \r
376         for(BoneInfo bone : boneList){\r
377             dumpBone(bone);\r
378         }\r
379 \r
380         flush();\r
381 \r
382         return;\r
383     }\r
384 \r
385     /**\r
386      * 個別のボーン情報を出力する。\r
387      * @param bone ボーン情報\r
388      * @throws IOException 出力エラー\r
389      * @throws IllegalPmdTextException ボーン名が長すぎる\r
390      */\r
391     private void dumpBone(BoneInfo bone)\r
392             throws IOException, IllegalPmdTextException{\r
393         String boneName = bone.getBoneName().getPrimaryText();\r
394         dumpText(boneName, PmdLimits.MAXBYTES_BONENAME);\r
395 \r
396         BoneInfo prev = bone.getPrevBone();\r
397         if(prev != null) dumpSerialIdAsShort(prev);\r
398         else             dumpShort(NOPREVBONE_ID);\r
399 \r
400         BoneInfo next = bone.getNextBone();\r
401         if(next != null) dumpSerialIdAsShort(next);\r
402         else             dumpShort(NONEXTBONE_ID);\r
403 \r
404         BoneType type = bone.getBoneType();\r
405         dumpByte(type.encode());\r
406 \r
407         if(type == BoneType.LINKEDROT){\r
408             int ratio = bone.getRotationRatio();\r
409             dumpShort(ratio);\r
410         }else{\r
411             BoneInfo ik = bone.getIKBone();\r
412             if(ik != null) dumpSerialIdAsShort(ik);\r
413             else           dumpShort(NOIKBONE_ID);\r
414         }\r
415 \r
416         Pos3d position = bone.getPosition();\r
417         dumpPos3d(position);\r
418 \r
419         return;\r
420     }\r
421 \r
422     /**\r
423      * IKチェーンリストを出力する。\r
424      * @param model モデルデータ\r
425      * @throws IOException 出力エラー\r
426      */\r
427     private void dumpIKChainList(PmdModel model)\r
428             throws IOException{\r
429         List<IKChain> ikChainList = model.getIKChainList();\r
430 \r
431         int ikNum = ikChainList.size();\r
432         dumpShort(ikNum);\r
433 \r
434         for(IKChain chain : ikChainList){\r
435             dumpIKChain(chain);\r
436         }\r
437 \r
438         flush();\r
439 \r
440         return;\r
441     }\r
442 \r
443     /**\r
444      * IKチェーンを出力する。\r
445      * @param chain IKチェーン\r
446      * @throws IOException 出力エラー\r
447      */\r
448     // TODO ボーンリストから自動抽出できる情報ではないのか?\r
449     private void dumpIKChain(IKChain chain)\r
450             throws IOException{\r
451         BoneInfo ikBone = chain.getIkBone();\r
452         dumpSerialIdAsShort(ikBone);\r
453 \r
454         List<BoneInfo> boneList = chain.getChainedBoneList();\r
455 \r
456         BoneInfo bone1st = boneList.get(0);\r
457         dumpSerialIdAsShort(bone1st);\r
458 \r
459         int boneNum = boneList.size();\r
460         dumpByte(boneNum - 1);\r
461 \r
462         int depth = chain.getIKDepth();\r
463         float weight = chain.getIKWeight();\r
464 \r
465         dumpShort(depth);\r
466         dumpFloat(weight);\r
467 \r
468         for(int idx = 1; idx < boneNum; idx++){ // リストの2番目以降全て\r
469             BoneInfo bone = boneList.get(idx);\r
470             dumpSerialIdAsShort(bone);\r
471         }\r
472 \r
473         return;\r
474     }\r
475 \r
476     /**\r
477      * モーフリストを出力する。\r
478      * @param model モデルデータ\r
479      * @throws IOException 出力エラー\r
480      * @throws IllegalPmdTextException モーフ名が長すぎる\r
481      */\r
482     private void dumpMorphList(PmdModel model)\r
483             throws IOException, IllegalPmdTextException{\r
484         Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();\r
485         Set<MorphType> typeSet = morphMap.keySet();\r
486         List<MorphVertex> mergedMorphVertexList = model.mergeMorphVertex();\r
487 \r
488         int totalMorphPart = 0;\r
489         for(MorphType type : typeSet){\r
490             List<MorphPart> partList = morphMap.get(type);\r
491             if(partList == null) continue;\r
492             totalMorphPart += partList.size();\r
493         }\r
494 \r
495         if(totalMorphPart <= 0){\r
496             dumpShort(0);\r
497             return;\r
498         }else{\r
499             totalMorphPart++;  // baseの分\r
500             dumpShort(totalMorphPart);\r
501         }\r
502 \r
503         dumpText("base", PmdLimits.MAXBYTES_MORPHNAME);\r
504         int totalVertex = mergedMorphVertexList.size();\r
505         dumpInt(totalVertex);\r
506         dumpByte(MorphType.BASE.encode());\r
507         for(MorphVertex morphVertex : mergedMorphVertexList){\r
508             Vertex baseVertex = morphVertex.getBaseVertex();\r
509             dumpInt(baseVertex.getSerialNumber());\r
510             dumpPos3d(baseVertex.getPosition());\r
511         }\r
512 \r
513         for(MorphType type : typeSet){\r
514             List<MorphPart> partList = morphMap.get(type);\r
515             if(partList == null) continue;\r
516             for(MorphPart part : partList){\r
517                 dumpText(part.getMorphName().getPrimaryText(),\r
518                          PmdLimits.MAXBYTES_MORPHNAME );\r
519                 List<MorphVertex> morphVertexList = part.getMorphVertexList();\r
520                 dumpInt(morphVertexList.size());\r
521                 dumpByte(part.getMorphType().encode());\r
522 \r
523                 for(MorphVertex morphVertex : morphVertexList){\r
524                     dumpInt(morphVertex.getSerialNumber());\r
525                     dumpPos3d(morphVertex.getOffset());\r
526                 }\r
527             }\r
528         }\r
529 \r
530         flush();\r
531 \r
532         return;\r
533     }\r
534 \r
535     /**\r
536      * モーフグループを出力する。\r
537      * @param model モデルデータ\r
538      * @throws IOException 出力エラー\r
539      */\r
540     private void dumpMorphGroup(PmdModel model)\r
541             throws IOException{\r
542         Map<MorphType, List<MorphPart>> morphMap = model.getMorphMap();\r
543         Set<MorphType> typeSet = morphMap.keySet();\r
544 \r
545         int totalMorph = 0;\r
546         for(MorphType type : typeSet){\r
547             List<MorphPart> partList = morphMap.get(type);\r
548             if(partList == null) continue;\r
549             totalMorph += partList.size();\r
550         }\r
551         dumpByte(totalMorph);\r
552 \r
553         List<MorphType> typeList = new LinkedList<MorphType>();\r
554         for(MorphType type : typeSet){\r
555             assert ! type.isBase();\r
556             typeList.add(type);\r
557         }\r
558         Collections.reverse(typeList);  // 一応本家と互換性を\r
559 \r
560         for(MorphType type : typeList){\r
561             List<MorphPart> partList = morphMap.get(type);\r
562             if(partList == null) continue;\r
563             for(MorphPart part : partList){\r
564                 dumpSerialIdAsShort(part);\r
565             }\r
566         }\r
567 \r
568         flush();\r
569 \r
570         return;\r
571     }\r
572 \r
573     /**\r
574      * ボーングループリストを出力する。\r
575      * デフォルトボーングループ内訳は出力されない。\r
576      * @param model モデルデータ\r
577      * @throws IOException 出力エラー\r
578      * @throws IllegalPmdTextException ボーングループ名が長すぎる\r
579      */\r
580     private void dumpBoneGroupList(PmdModel model)\r
581             throws IOException, IllegalPmdTextException{\r
582         List<BoneGroup> groupList = model.getBoneGroupList();\r
583         int groupNum = groupList.size();\r
584         dumpByte(groupNum - 1);\r
585 \r
586         int dispBoneNum = 0;\r
587         for(BoneGroup group : groupList){\r
588             if(group.isDefaultBoneGroup()) continue;\r
589             dumpText(group.getGroupName().getPrimaryText(),\r
590                      PmdLimits.MAXBYTES_BONEGROUPNAME, LFFILLER );\r
591             dispBoneNum += group.getBoneList().size();\r
592         }\r
593         dumpInt(dispBoneNum);\r
594 \r
595         for(BoneGroup group : groupList){\r
596             if(group.isDefaultBoneGroup()) continue;\r
597             for(BoneInfo bone : group){\r
598                 dumpSerialIdAsShort(bone);\r
599                 int groupId = group.getSerialNumber();\r
600                 dumpByte(groupId);\r
601             }\r
602         }\r
603 \r
604         flush();\r
605 \r
606         return;\r
607     }\r
608 \r
609     /**\r
610      * 各種通し番号をshort値で出力する。\r
611      * short値に収まらない上位ビットは捨てられる。\r
612      * @param obj 番号づけられたオブジェクト\r
613      * @throws IOException 出力エラー\r
614      */\r
615     protected void dumpSerialIdAsShort(SerialNumbered obj)\r
616             throws IOException{\r
617         int serialId = obj.getSerialNumber();\r
618         dumpShort(serialId);\r
619         return;\r
620     }\r
621 \r
622     /**\r
623      * 2次元位置情報を出力する。\r
624      * @param position 2次元位置情報\r
625      * @throws IOException 出力エラー\r
626      */\r
627     protected void dumpPos2d(Pos2d position) throws IOException{\r
628         float xPos = position.getXPos();\r
629         float yPos = position.getYPos();\r
630 \r
631         dumpFloat(xPos);\r
632         dumpFloat(yPos);\r
633 \r
634         return;\r
635     }\r
636 \r
637     /**\r
638      * 3次元位置情報を出力する。\r
639      * @param position 3次元位置情報\r
640      * @throws IOException 出力エラー\r
641      */\r
642     protected void dumpPos3d(Pos3d position) throws IOException{\r
643         float xPos = position.getXPos();\r
644         float yPos = position.getYPos();\r
645         float zPos = position.getZPos();\r
646 \r
647         dumpFloat(xPos);\r
648         dumpFloat(yPos);\r
649         dumpFloat(zPos);\r
650 \r
651         return;\r
652     }\r
653 \r
654     /**\r
655      * 3次元ベクトル情報を出力する。\r
656      * @param vector 3次元ベクトル\r
657      * @throws IOException 出力エラー\r
658      */\r
659     protected void dumpVec3d(Vec3d vector) throws IOException{\r
660         float xVal = vector.getXVal();\r
661         float yVal = vector.getYVal();\r
662         float zVal = vector.getZVal();\r
663 \r
664         dumpFloat(xVal);\r
665         dumpFloat(yVal);\r
666         dumpFloat(zVal);\r
667 \r
668         return;\r
669     }\r
670 \r
671 }\r