OSDN Git Service

implement pmd_export texture.
[meshio/meshio.git] / src / pmd.cpp
1 #include "pmd.h"
2 #include <iostream>
3 #include "text.h"
4
5 namespace meshio {
6 namespace pmd {
7
8 std::wstring 
9         Material::getTexture()const
10         {
11                 return text::trim(text::to_WideChar(CP_OEMCP, 
12                                         std::string(texture, texture+20)));
13         }
14
15 std::wstring 
16         Bone::getName()const
17         {
18                 return text::trim(text::to_WideChar(CP_OEMCP, 
19                                         std::string(name, name+20)));
20         }
21
22 std::wstring 
23         Morph::getName()const
24         {
25                 return text::trim(text::to_WideChar(CP_OEMCP, 
26                                         std::string(name, name+20)));
27         }
28
29 void
30         Morph::append(int index, float x, float y, float z)
31         {
32                 indices.push_back(index);
33                 pos_list.push_back(Vector3(x, y, z));
34         }
35
36 std::wstring 
37         IO::getName()const
38         {
39                 return text::trim(text::to_WideChar(CP_OEMCP, 
40                                         std::string(name, name+20)));
41         }
42
43 std::wstring 
44         IO::getEnglishName()const
45         {
46                 return text::trim(text::to_WideChar(CP_OEMCP, 
47                                         std::string(english_name, english_name+20)));
48         }
49
50 std::wstring 
51         RigidBody::getName()const
52         {
53                 return text::trim(text::to_WideChar(CP_OEMCP, 
54                                         std::string(name, name+20)));
55         }
56
57 std::wstring 
58         Constraint::getName()const
59         {
60                 return text::trim(text::to_WideChar(CP_OEMCP, 
61                                         std::string(name, name+20)));
62         }
63
64 // 38bytes
65 template<class READER>
66         void
67         read(READER &reader, Vertex &v)
68         {
69                 unsigned int pos=reader.getPos();
70                 reader.get(v.pos);
71                 reader.get(v.normal);
72                 reader.get(v.uv);
73                 reader.get(v.bone0);
74                 reader.get(v.bone1);
75                 reader.get(v.weight0);
76                 reader.get(v.edge_flag);
77                 assert(reader.getPos()-pos==38);
78         }
79
80
81 // 70bytes
82 template<class READER>
83         void
84         read(READER &reader, Material &m)
85         {
86                 unsigned int pos=reader.getPos();
87                 reader.get(m.diffuse);
88                 reader.get(m.shinness);
89                 reader.get(m.specular);
90                 reader.get(m.ambient);
91                 reader.get(m.toon_index);
92                 reader.get(m.flag);
93                 reader.get(m.vertex_count);
94                 text::copyStringAndFillZero(m.texture, reader.getString(20));
95                 assert(reader.getPos()-pos==70);
96         }
97
98 // 39bytes
99 template<class READER>
100         void
101         read(READER &reader, Bone &b)
102         {
103                 unsigned int pos=reader.getPos();
104                 text::copyStringAndFillZero(b.name, reader.getString(20));
105                 reader.get(b.parent_index);
106                 reader.get(b.tail_index);
107                 b.type=static_cast<BONE_TYPE>(reader.getUchar());
108                 reader.get(b.ik_index);
109                 reader.get(b.pos);
110                 assert(reader.getPos()-pos==39);
111         }
112
113 // 11+2xIK_COUNT bytes
114 template<class READER>
115         void
116         read(READER &reader, IK &ik)
117         {
118                 // 11bytes
119                 reader.get(ik.index);
120                 reader.get(ik.target);
121                 reader.get(ik.length);
122                 reader.get(ik.iterations);
123                 reader.get(ik.weight);
124                 // 2 x length bytes
125                 for(unsigned short j=0; j<ik.length; ++j){
126                         ik.children.push_back(reader.getUshort());
127                 }
128         }
129
130 // 25+12xMORPH_COUNT bytes
131 template<class READER>
132         void
133         read(READER &reader, Morph &m)
134         {
135                 // 25bytes
136                 text::copyStringAndFillZero(m.name, reader.getString(20));
137                 reader.get(m.vertex_count);
138                 m.type=static_cast<MORPH_TYPE>(reader.getUchar());
139                 // 12 x vertex_count bytes
140                 for(unsigned short i=0; i<m.vertex_count; ++i){
141                         m.indices.push_back(reader.getUint());
142                         m.pos_list.push_back(Vector3());
143                         reader.get(m.pos_list.back());
144                 }
145         }
146
147 // 83bytes
148 template<class READER>
149         void
150         read(READER &reader, RigidBody &r)
151         {
152                 unsigned int pos=reader.getPos();
153                 text::copyStringAndFillZero(r.name, reader.getString(20));
154                 reader.get(r.boneIndex);
155                 reader.get(r.group);
156                 reader.get(r.target);
157                 r.shapeType=static_cast<SHAPE_TYPE>(reader.getUchar());
158                 reader.get(r.w);
159                 reader.get(r.h);
160                 reader.get(r.d);
161                 reader.get(r.position);
162                 reader.get(r.rotation);
163                 reader.get(r.weight);
164                 reader.get(r.linearDamping);
165                 reader.get(r.angularDamping);
166                 reader.get(r.restitution);
167                 reader.get<float>(r.friction);
168                 r.processType=static_cast<PROCESS_TYPE>(reader.getUchar());
169                 assert(reader.getPos()-pos==83);
170         }
171
172 // 124bytes
173 template<class READER>
174         void
175         read(READER &reader, Constraint &c)
176         {
177                 unsigned int base_pos=reader.getPos();
178                 text::copyStringAndFillZero(c.name, reader.getString(20));
179                 reader.get(c.rigidA);
180                 reader.get(c.rigidB);
181                 reader.get(c.pos);
182                 reader.get(c.rot);
183                 reader.get(c.constraintPosMin);
184                 reader.get(c.constraintPosMax);
185                 reader.get(c.constraintRotMin);
186                 reader.get(c.constraintRotMax);
187                 reader.get(c.springPos);
188                 reader.get(c.springRot);
189                 assert(reader.getPos()-base_pos==124);
190         }
191
192 class Impl
193 {
194         IO &io_;
195         binary::IReader &reader_;
196
197 public:
198         Impl(IO &io, binary::IReader &reader)
199                 : io_(io), reader_(reader)
200                 {}
201
202         bool parse()
203         {
204                 if(!parseHeader()){
205                         return false;
206                 }
207                 if(!parseVertices()){
208                         return false;
209                 }
210                 if(!parseIndices()){
211                         return false;
212                 }
213                 if(!parseMaterials()){
214                         return false;
215                 }
216                 if(!parseBones()){
217                         return false;
218                 }
219                 if(!parseIK()){
220                         return false;
221                 }
222                 if(!parseMorph()){
223                         return false;
224                 }
225                 if(!parseFaceList()){
226                         return false;
227                 }
228                 if(!parseBoneNameList()){
229                         return false;
230                 }
231                 if(!parseBoneList()){
232                         return false;
233                 }
234                 if(reader_.isEnd()){
235                         return true;
236                 }
237
238                 ////////////////////////////////////////////////////////////
239                 // extended data
240                 ////////////////////////////////////////////////////////////
241                 // english
242                 ////////////////////////////////////////////////////////////
243                 if(reader_.getChar()){
244                         if(!parseEnglishName()){
245                                 return false;
246                         }
247                         if(!parseEnglishBone()){
248                                 return false;
249                         }
250                         if(!parseEnglishMorph()){
251                                 return false;
252                         }
253                         if(!parseEnglishBoneList()){
254                                 return false;
255                         }
256                 }
257                 if(reader_.isEnd()){
258                         return true;
259                 }
260
261                 // toone texture
262                 ////////////////////////////////////////////////////////////
263                 if(!parseToonTextures()){
264                         return false;
265                 }
266                 if(reader_.isEnd()){
267                         return true;
268                 }
269
270                 // physics
271                 ////////////////////////////////////////////////////////////
272                 if(!parseRigid()){
273                         return false;
274                 }
275                 if(!parseConstraint()){
276                         return false;
277                 }
278
279                 // end
280                 assert(reader_.isEnd());
281
282                 return true;
283         }
284
285 private:
286         bool parseConstraint()
287         {
288                 unsigned int count=reader_.getUint();
289                 for(unsigned int i=0; i<count; ++i){
290                         io_.constraints.push_back(Constraint());
291                         read(reader_, io_.constraints.back());
292                 }
293                 return true;
294         }
295
296         bool parseRigid()
297         {
298                 unsigned int count=reader_.getUint();
299                 for(unsigned int i=0; i<count; ++i){
300                         io_.rigidbodies.push_back(RigidBody());
301                         read(reader_, io_.rigidbodies.back());
302                 }
303                 return true;
304         }
305
306         bool parseToonTextures()
307         {
308                 for(size_t i=0; i<10; ++i){
309                         reader_.getString(100);
310                 }
311                 return true;
312         }
313
314         bool parseEnglishBoneList()
315         {
316                 for(size_t i=0; i<io_.bone_display_name_list.size(); ++i){
317                         text::copyStringAndFillZero(
318                                         io_.bone_display_name_list[i].english_name, 
319                                         reader_.getString(50));
320                 }
321                 return true;
322         }
323
324         bool parseEnglishMorph()
325         {
326                 int count=io_.morph_list.size()-1;
327                 for(int i=0; i<count; ++i){
328                         text::copyStringAndFillZero(
329                                         io_.morph_list[i].english_name, reader_.getString(20));
330                 }
331                 return true;
332         }
333
334         bool parseEnglishBone()
335         {
336                 for(size_t i=0; i<io_.bones.size(); ++i){
337                         text::copyStringAndFillZero(
338                                         io_.bones[i].english_name, reader_.getString(20));
339                 }
340                 return true;
341         }
342
343         bool parseEnglishName()
344         {
345                 text::copyStringAndFillZero(io_.english_name, 
346                                 reader_.getString(20));
347                 text::copyStringAndFillZero(io_.english_comment, 
348                                 reader_.getString(256));
349                 return true;
350         }
351
352         bool parseBoneList()
353         {
354                 unsigned int count=reader_.getUint();
355                 for(unsigned int i=0; i<count; ++i){
356                         unsigned short bone=reader_.getUshort();
357                         unsigned char disp=reader_.getUchar();
358                         io_.bone_display_list.push_back(std::make_pair(bone, disp));
359                 }
360                 return true;
361         }
362
363         bool parseBoneNameList()
364         {
365                 unsigned int count=reader_.getUchar();
366                 for(unsigned int i=0; i<count; ++i){
367                         io_.bone_display_name_list.push_back(BoneDisplayName());
368                         text::copyStringAndFillZero(
369                                         io_.bone_display_name_list.back().name,
370                                         reader_.getString(50));
371                 }
372                 return true;
373         }
374
375         bool parseFaceList()
376         {
377                 unsigned int count=reader_.getUchar();
378                 for(unsigned int i=0; i<count; ++i){
379                         io_.face_list.push_back(reader_.getUshort());
380                 }
381                 return true;
382         }
383
384         bool parseMorph()
385         {
386                 unsigned int count=reader_.getUshort();
387                 for(unsigned int i=0; i<count; ++i){
388                         io_.morph_list.push_back(Morph());
389                         read(reader_, io_.morph_list.back());
390                 }
391                 return true;
392         }
393
394         bool parseIK()
395         {
396                 unsigned int count=reader_.getUshort();
397                 for(unsigned int i=0; i<count; ++i){
398                         io_.ik_list.push_back(IK());
399                         read(reader_, io_.ik_list.back());
400                 }
401                 return true;
402         }
403
404         bool parseBones()
405         {
406                 unsigned int count=reader_.getUshort();
407                 for(unsigned int i=0; i<count; ++i){
408                         io_.bones.push_back(Bone());
409                         read(reader_, io_.bones.back());
410                 }
411                 return true;
412         }
413
414         bool parseMaterials()
415         {
416                 unsigned int count=reader_.getUint();
417                 for(unsigned int i=0; i<count; ++i){
418                         io_.materials.push_back(new Material());
419                         read(reader_, *io_.materials.back());
420                 }
421                 return true;
422         }
423
424         bool parseIndices()
425         {
426                 unsigned int count=reader_.getUint();
427                 for(unsigned int i=0; i<count; ++i){
428                         io_.indices.push_back(reader_.getUshort());
429                 }
430                 return true;
431         }
432
433         bool parseVertices()
434         {
435                 unsigned int count=reader_.getUint();
436                 for(unsigned int i=0; i<count; ++i){
437                         io_.vertices.push_back(Vertex());
438                         read(reader_, io_.vertices.back());
439                 }
440                 return true;
441         }
442
443         bool parseHeader()
444         {
445                 if(reader_.getString(3)!="Pmd"){
446                         //std::cout << "invalid pmd" << std::endl;
447                         return false;
448                 }
449                 reader_.get(io_.version);
450                 if(io_.version!=1.0){
451                         std::cout << "invalid vesion: " << io_.version <<std::endl;
452                         return false;
453                 }
454                 text::copyStringAndFillZero(io_.name, reader_.getString(20));
455                 text::copyStringAndFillZero(io_.comment, reader_.getString(256));
456
457                 return true;
458         }
459
460 };
461
462 ///////////////////////////////////////////////////////////////////////////////
463 // IO
464 ///////////////////////////////////////////////////////////////////////////////
465 IO::IO()
466 : version(0)
467 {}
468
469 IO::~IO()
470 {
471         for(size_t i=0; i<materials.size(); ++i){
472                 delete materials[i];
473         }
474         materials.clear();
475 }
476
477 bool IO::read(binary::IReader &input)
478 {
479         Impl impl(*this, input);
480         if(!impl.parse()){
481                 return false;
482         }
483
484         ////////////////////////////////////////////////////////////
485         // post process
486         ////////////////////////////////////////////////////////////
487         if(!morph_list.empty()){
488                 // validate morph
489                 assert(morph_list[0].type==MORPH_BASE);
490                 // check base
491                 Morph &base=morph_list[0];
492                 for(size_t i=0; i<base.vertex_count; ++i){
493                         assert(vertices[base.indices[i]].pos==base.pos_list[i]);
494                 }
495                 // check each face
496                 for(size_t i=1; i<morph_list.size(); ++i){
497                         Morph &m=morph_list[i];
498                         assert(m.type!=MORPH_BASE);
499                 }
500         }
501         ////////////////////////////////////////////////////////////
502         // setup bone
503         ////////////////////////////////////////////////////////////
504         for(size_t i=0; i<bones.size(); ++i){
505                 Bone &bone=bones[i];
506                 bone.index=i;
507                 if(bone.parent_index!=0xFFFF){
508                         bone.parent=&bones[bone.parent_index];
509                         bone.parent->children.push_back(&bone);
510                 }
511                 if(bone.tail_index!=0){
512                         bone.tail=bones[bone.tail_index].pos;
513                 }
514         }
515
516         return true;
517 }
518
519 /*
520 bool IO::read(const char *path)
521 {
522         std::vector<char> all;
523         binary::readAll(path, all);
524         if(all.empty()){
525                 return false;
526         }
527         binary::MemoryReader reader(&all[0], all.size());
528         return read(reader);
529 }
530 */
531
532 bool IO::read(const wchar_t *path)
533 {
534         std::vector<char> all;
535         binary::readAll(path, all);
536         std::cerr << all.size() << "bytes" << std::endl;
537         if(all.empty()){
538                 return false;
539         }
540         binary::MemoryReader reader(&all[0], all.size());
541         return read(reader);
542 }
543
544 bool IO::write(binary::IWriter &w)
545 {
546         w.write("Pmd", 3);
547         w.writeValue<float>(version);
548         w.write(name, 20);
549         w.write(comment, 256);
550
551         // vertices
552         //std::cout << "vertices" << std::endl;
553         w.writeValue<DWORD>(vertices.size());
554         for(size_t i=0; i<vertices.size(); ++i){
555                 Vertex &v=vertices[i];
556                 w.writeValue<float>(v.pos.x);
557                 w.writeValue<float>(v.pos.y);
558                 w.writeValue<float>(v.pos.z);
559                 w.writeValue<float>(v.normal.x);
560                 w.writeValue<float>(v.normal.y);
561                 w.writeValue<float>(v.normal.z);
562                 w.writeValue<float>(v.uv.x);
563                 w.writeValue<float>(v.uv.y);
564                 w.writeValue<WORD>(v.bone0);
565                 w.writeValue<WORD>(v.bone1);
566                 w.writeValue<BYTE>(v.weight0);
567                 w.writeValue<BYTE>(v.edge_flag);
568         }
569
570         // faces
571         //std::cout << "faces" << std::endl;
572         w.writeValue<DWORD>(indices.size());
573         if(indices.size()>0){
574                 w.writeArray<WORD>(&indices[0], indices.size());
575         }
576
577         // materials
578         //std::cout << "materials" << std::endl;
579         w.writeValue<DWORD>(materials.size());
580         for(size_t i=0; i<materials.size(); ++i){
581                 Material &m=*materials[i];
582                 w.writeValue<float>(m.diffuse.r);
583                 w.writeValue<float>(m.diffuse.g);
584                 w.writeValue<float>(m.diffuse.b);
585                 w.writeValue<float>(m.diffuse.a);
586                 w.writeValue<float>(m.shinness);
587                 w.writeValue<float>(m.specular.r);
588                 w.writeValue<float>(m.specular.g);
589                 w.writeValue<float>(m.specular.b);
590                 w.writeValue<float>(m.ambient.r);
591                 w.writeValue<float>(m.ambient.g);
592                 w.writeValue<float>(m.ambient.b);
593                 w.writeValue<BYTE>(m.toon_index);
594                 w.writeValue<BYTE>(m.flag);
595                 w.writeValue<DWORD>(m.vertex_count);
596                 w.writeArray<char>(m.texture, 20);
597         }
598
599         // bones
600         //std::cout << "bones" << std::endl;
601         w.writeValue<WORD>(bones.size());
602         for(size_t i=0; i<bones.size(); ++i){
603                 Bone &b=bones[i];
604                 w.writeArray<char>(b.name, 20);
605                 w.writeValue<WORD>(b.parent_index);
606                 w.writeValue<WORD>(b.tail_index);
607                 w.writeValue<BYTE>(b.type);
608                 w.writeValue<WORD>(b.ik_index);
609                 w.writeValue<float>(b.pos.x);
610                 w.writeValue<float>(b.pos.y);
611                 w.writeValue<float>(b.pos.z);
612         }
613
614         // ik
615         //std::cout << "ik" << std::endl;
616         w.writeValue<WORD>(ik_list.size());
617         for(size_t i=0; i<ik_list.size(); ++i){
618                 IK &ik=ik_list[i];
619                 w.writeValue<WORD>(ik.index);
620                 w.writeValue<WORD>(ik.target);
621                 w.writeValue<BYTE>(ik.length);
622                 w.writeValue<WORD>(ik.iterations);
623                 w.writeValue<float>(ik.weight);
624                 WORD parent_index=bones[ik.target].parent_index;
625                 for(size_t j=0; j<ik.length; 
626                                 ++j, parent_index=bones[parent_index].parent_index){
627                         w.writeValue<WORD>(parent_index);
628                 }
629         }
630
631         // morph
632         //std::cout << "morph" << std::endl;
633         w.writeValue<WORD>(morph_list.size());
634         for(size_t i=0; i<morph_list.size(); ++i){
635                 Morph &m=morph_list[i];
636                 w.writeArray<char>(m.name, 20);
637                 w.writeValue<DWORD>(m.indices.size());
638                 w.writeValue<BYTE>(m.type);
639                 for(size_t j=0; j<m.indices.size(); ++j){
640                         w.writeValue<DWORD>(m.indices[j]);
641                         Vector3 &pos=m.pos_list[j];
642                         w.writeValue<float>(pos.x);
643                         w.writeValue<float>(pos.y);
644                         w.writeValue<float>(pos.z);
645                 }
646         }
647
648         // face list
649         //std::cout << "face list" << std::endl;
650         w.writeValue<BYTE>(face_list.size());
651         if(face_list.size()>0){
652                 w.writeArray<WORD>(&face_list[0], face_list.size());
653         }
654
655         // bone naem list
656         //std::cout << "bone name list" << std::endl;
657         w.writeValue<BYTE>(bone_display_name_list.size());
658         for(size_t i=0; i<bone_display_name_list.size(); ++i){
659                 // 50bytes
660                 w.writeArray<char>(bone_display_name_list[i].name, 50);
661         }
662
663         // bone list
664         //std::cout << "bone list" << std::endl;
665         w.writeValue<DWORD>(bone_display_list.size());
666         for(size_t i=0; i<bone_display_list.size(); ++i){
667                 w.writeValue<WORD>(bone_display_list[i].first);
668                 w.writeValue<BYTE>(bone_display_list[i].second);
669         }
670
671         ////////////////////////////////////////////////////////////
672         // extend
673         ////////////////////////////////////////////////////////////
674         w.writeValue<char>(0x01);
675
676         ////////////////////////////////////////////////////////////
677         // english names
678         ////////////////////////////////////////////////////////////
679         w.writeArray<char>(english_name, 20);
680         w.writeArray<char>(english_comment, 256);
681
682         for(size_t i=0; i<bones.size(); ++i){
683                 w.writeArray<char>(bones[i].english_name, 20);
684         }
685
686         for(size_t i=1; i<morph_list.size(); ++i){
687                 w.writeArray<char>(morph_list[i].english_name, 20);
688         }
689
690         for(size_t i=0; i<bone_display_name_list.size(); ++i){
691                 w.writeArray<char>(bone_display_name_list[i].english_name, 50);
692         }
693
694         ////////////////////////////////////////////////////////////
695         // toon textures
696         ////////////////////////////////////////////////////////////
697         for(size_t i=0; i<10; ++i){
698                 w.writeArray<char>(toon_textures[i].name, 100);
699         }
700
701         ////////////////////////////////////////////////////////////
702         // rigid bodies
703         ////////////////////////////////////////////////////////////
704         w.writeValue<DWORD>(rigidbodies.size());
705         for(size_t i=0; i<rigidbodies.size(); ++i){
706                 RigidBody &rb=rigidbodies[i];
707                 w.writeArray<char>(rb.name, 20);
708                 w.writeValue<WORD>(rb.boneIndex);
709                 w.writeValue<BYTE>(rb.group);
710                 w.writeValue<WORD>(rb.target);
711                 w.writeValue<BYTE>(rb.shapeType);
712                 w.writeValue<float>(rb.w);
713                 w.writeValue<float>(rb.h);
714                 w.writeValue<float>(rb.d);
715                 w.writeValue<float>(rb.position.x);
716                 w.writeValue<float>(rb.position.y);
717                 w.writeValue<float>(rb.position.z);
718                 w.writeValue<float>(rb.rotation.x);
719                 w.writeValue<float>(rb.rotation.y);
720                 w.writeValue<float>(rb.rotation.z);
721                 w.writeValue<float>(rb.weight);
722                 w.writeValue<float>(rb.linearDamping);
723                 w.writeValue<float>(rb.angularDamping);
724                 w.writeValue<float>(rb.restitution);
725                 w.writeValue<float>(rb.friction);
726                 w.writeValue<BYTE>(rb.processType);
727         }
728
729         ////////////////////////////////////////////////////////////
730         // constraints
731         ////////////////////////////////////////////////////////////
732         w.writeValue<DWORD>(constraints.size());
733         for(size_t i=0; i<constraints.size(); ++i){
734                 Constraint &c=constraints[i];
735                 w.writeArray<char>(c.name, 20);
736                 w.writeValue<DWORD>(c.rigidA);
737                 w.writeValue<DWORD>(c.rigidB);
738                 w.writeValue<float>(c.pos.x);
739                 w.writeValue<float>(c.pos.y);
740                 w.writeValue<float>(c.pos.z);
741                 w.writeValue<float>(c.rot.x);
742                 w.writeValue<float>(c.rot.y);
743                 w.writeValue<float>(c.rot.z);
744                 w.writeValue<float>(c.constraintPosMin.x);
745                 w.writeValue<float>(c.constraintPosMin.y);
746                 w.writeValue<float>(c.constraintPosMin.z);
747                 w.writeValue<float>(c.constraintPosMax.x);
748                 w.writeValue<float>(c.constraintPosMax.y);
749                 w.writeValue<float>(c.constraintPosMax.z);
750                 w.writeValue<float>(c.constraintRotMin.x);
751                 w.writeValue<float>(c.constraintRotMin.y);
752                 w.writeValue<float>(c.constraintRotMin.z);
753                 w.writeValue<float>(c.constraintRotMax.x);
754                 w.writeValue<float>(c.constraintRotMax.y);
755                 w.writeValue<float>(c.constraintRotMax.z);
756                 w.writeValue<float>(c.springPos.x);
757                 w.writeValue<float>(c.springPos.y);
758                 w.writeValue<float>(c.springPos.z);
759                 w.writeValue<float>(c.springRot.x);
760                 w.writeValue<float>(c.springRot.y);
761                 w.writeValue<float>(c.springRot.z);
762         }
763
764         return true;
765 }
766
767 bool IO::write(const char *path)
768 {
769         binary::FileWriter w(path);
770         return write(w);
771 }
772
773 bool IO::write(const wchar_t *path)
774 {
775         binary::FileWriter w(path);
776         return write(w);
777 }
778
779 const Vector2* IO::getUV(int index)const
780 {
781         return &vertices[index].uv;
782 }
783
784 void Bone::setName(const char *src)
785 {
786         strncpy(name, src, 20);
787 }
788
789 void BoneDisplayName::setName(const char *src)
790 {
791         strncpy(name, src, 20);
792 }
793
794 void BoneDisplayName::setEnglishName(const char *src)
795 {
796         strncpy(english_name, src, 20);
797 }
798
799 void Morph::setName(const char *src)
800 {
801         strncpy(name, src, 20);
802 }
803
804 void Morph::setEnglishName(const char *src)
805 {
806         strncpy(english_name, src, 20);
807 }
808
809 void RigidBody::setName(const char *src)
810 {
811         strncpy(name, src, 20);
812 }
813
814 void Constraint::setName(const char *src)
815 {
816         strncpy(name, src, 20);
817 }
818
819 void Material::setTexture(const char *src)
820 {
821         strncpy(texture, src, 20);
822 }
823
824
825 } // namespace
826 } // namespace
827