1 | /* |
2 | Open Asset Import Library (assimp) |
3 | ---------------------------------------------------------------------- |
4 | |
5 | Copyright (c) 2006-2017, assimp team |
6 | |
7 | All rights reserved. |
8 | |
9 | Redistribution and use of this software in source and binary forms, |
10 | with or without modification, are permitted provided that the |
11 | following conditions are met: |
12 | |
13 | * Redistributions of source code must retain the above |
14 | copyright notice, this list of conditions and the |
15 | following disclaimer. |
16 | |
17 | * Redistributions in binary form must reproduce the above |
18 | copyright notice, this list of conditions and the |
19 | following disclaimer in the documentation and/or other |
20 | materials provided with the distribution. |
21 | |
22 | * Neither the name of the assimp team, nor the names of its |
23 | contributors may be used to endorse or promote products |
24 | derived from this software without specific prior |
25 | written permission of the assimp team. |
26 | |
27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
38 | |
39 | ---------------------------------------------------------------------- |
40 | */ |
41 | #pragma once |
42 | |
43 | #include <vector> |
44 | #include <string> |
45 | #include <memory> |
46 | #include <iostream> |
47 | #include <fstream> |
48 | #include "MMDCpp14.h" |
49 | |
50 | namespace pmd |
51 | { |
52 | class |
53 | { |
54 | public: |
55 | std::string ; |
56 | std::string ; |
57 | std::string ; |
58 | std::string ; |
59 | |
60 | bool (std::ifstream* stream) |
61 | { |
62 | char buffer[256]; |
63 | stream->read(buffer, 20); |
64 | name = std::string(buffer); |
65 | stream->read(buffer, 256); |
66 | comment = std::string(buffer); |
67 | return true; |
68 | } |
69 | |
70 | bool (std::ifstream* stream) |
71 | { |
72 | char buffer[256]; |
73 | stream->read(buffer, 20); |
74 | name_english = std::string(buffer); |
75 | stream->read(buffer, 256); |
76 | comment_english = std::string(buffer); |
77 | return true; |
78 | } |
79 | }; |
80 | |
81 | class PmdVertex |
82 | { |
83 | public: |
84 | float position[3]; |
85 | |
86 | float normal[3]; |
87 | |
88 | float uv[2]; |
89 | |
90 | uint16_t bone_index[2]; |
91 | |
92 | uint8_t bone_weight; |
93 | |
94 | bool edge_invisible; |
95 | |
96 | bool Read(std::ifstream* stream) |
97 | { |
98 | stream->read((char*) position, sizeof(float) * 3); |
99 | stream->read((char*) normal, sizeof(float) * 3); |
100 | stream->read((char*) uv, sizeof(float) * 2); |
101 | stream->read((char*) bone_index, sizeof(uint16_t) * 2); |
102 | stream->read((char*) &bone_weight, sizeof(uint8_t)); |
103 | stream->read((char*) &edge_invisible, sizeof(uint8_t)); |
104 | return true; |
105 | } |
106 | }; |
107 | |
108 | class PmdMaterial |
109 | { |
110 | public: |
111 | float diffuse[4]; |
112 | float power; |
113 | float specular[3]; |
114 | float ambient[3]; |
115 | uint8_t toon_index; |
116 | uint8_t edge_flag; |
117 | uint32_t index_count; |
118 | std::string texture_filename; |
119 | std::string sphere_filename; |
120 | |
121 | bool Read(std::ifstream* stream) |
122 | { |
123 | char buffer[20]; |
124 | stream->read((char*) &diffuse, sizeof(float) * 4); |
125 | stream->read((char*) &power, sizeof(float)); |
126 | stream->read((char*) &specular, sizeof(float) * 3); |
127 | stream->read((char*) &ambient, sizeof(float) * 3); |
128 | stream->read((char*) &toon_index, sizeof(uint8_t)); |
129 | stream->read((char*) &edge_flag, sizeof(uint8_t)); |
130 | stream->read((char*) &index_count, sizeof(uint32_t)); |
131 | stream->read((char*) &buffer, sizeof(char) * 20); |
132 | char* pstar = strchr(buffer, '*'); |
133 | if (NULL == pstar) |
134 | { |
135 | texture_filename = std::string(buffer); |
136 | sphere_filename.clear(); |
137 | } |
138 | else { |
139 | *pstar = 0; |
140 | texture_filename = std::string(buffer); |
141 | sphere_filename = std::string(pstar+1); |
142 | } |
143 | return true; |
144 | } |
145 | }; |
146 | |
147 | enum class BoneType : uint8_t |
148 | { |
149 | Rotation, |
150 | RotationAndMove, |
151 | IkEffector, |
152 | Unknown, |
153 | IkEffectable, |
154 | RotationEffectable, |
155 | IkTarget, |
156 | Invisible, |
157 | Twist, |
158 | RotationMovement |
159 | }; |
160 | |
161 | class PmdBone |
162 | { |
163 | public: |
164 | std::string name; |
165 | std::string name_english; |
166 | uint16_t parent_bone_index; |
167 | uint16_t tail_pos_bone_index; |
168 | BoneType bone_type; |
169 | uint16_t ik_parent_bone_index; |
170 | float bone_head_pos[3]; |
171 | |
172 | void Read(std::istream *stream) |
173 | { |
174 | char buffer[20]; |
175 | stream->read(buffer, 20); |
176 | name = std::string(buffer); |
177 | stream->read((char*) &parent_bone_index, sizeof(uint16_t)); |
178 | stream->read((char*) &tail_pos_bone_index, sizeof(uint16_t)); |
179 | stream->read((char*) &bone_type, sizeof(uint8_t)); |
180 | stream->read((char*) &ik_parent_bone_index, sizeof(uint16_t)); |
181 | stream->read((char*) &bone_head_pos, sizeof(float) * 3); |
182 | } |
183 | |
184 | void ReadExpantion(std::istream *stream) |
185 | { |
186 | char buffer[20]; |
187 | stream->read(buffer, 20); |
188 | name_english = std::string(buffer); |
189 | } |
190 | }; |
191 | |
192 | class PmdIk |
193 | { |
194 | public: |
195 | uint16_t ik_bone_index; |
196 | uint16_t target_bone_index; |
197 | uint16_t interations; |
198 | float angle_limit; |
199 | std::vector<uint16_t> ik_child_bone_index; |
200 | |
201 | void Read(std::istream *stream) |
202 | { |
203 | stream->read((char *) &ik_bone_index, sizeof(uint16_t)); |
204 | stream->read((char *) &target_bone_index, sizeof(uint16_t)); |
205 | uint8_t ik_chain_length; |
206 | stream->read((char*) &ik_chain_length, sizeof(uint8_t)); |
207 | stream->read((char *) &interations, sizeof(uint16_t)); |
208 | stream->read((char *) &angle_limit, sizeof(float)); |
209 | ik_child_bone_index.resize(ik_chain_length); |
210 | for (int i = 0; i < ik_chain_length; i++) |
211 | { |
212 | stream->read((char *) &ik_child_bone_index[i], sizeof(uint16_t)); |
213 | } |
214 | } |
215 | }; |
216 | |
217 | class PmdFaceVertex |
218 | { |
219 | public: |
220 | int vertex_index; |
221 | float position[3]; |
222 | |
223 | void Read(std::istream *stream) |
224 | { |
225 | stream->read((char *) &vertex_index, sizeof(int)); |
226 | stream->read((char *) position, sizeof(float) * 3); |
227 | } |
228 | }; |
229 | |
230 | enum class FaceCategory : uint8_t |
231 | { |
232 | Base, |
233 | Eyebrow, |
234 | Eye, |
235 | Mouth, |
236 | Other |
237 | }; |
238 | |
239 | class PmdFace |
240 | { |
241 | public: |
242 | std::string name; |
243 | FaceCategory type; |
244 | std::vector<PmdFaceVertex> vertices; |
245 | std::string name_english; |
246 | |
247 | void Read(std::istream *stream) |
248 | { |
249 | char buffer[20]; |
250 | stream->read(buffer, 20); |
251 | name = std::string(buffer); |
252 | int vertex_count; |
253 | stream->read((char*) &vertex_count, sizeof(int)); |
254 | stream->read((char*) &type, sizeof(uint8_t)); |
255 | vertices.resize(vertex_count); |
256 | for (int i = 0; i < vertex_count; i++) |
257 | { |
258 | vertices[i].Read(stream); |
259 | } |
260 | } |
261 | |
262 | void ReadExpantion(std::istream *stream) |
263 | { |
264 | char buffer[20]; |
265 | stream->read(buffer, 20); |
266 | name_english = std::string(buffer); |
267 | } |
268 | }; |
269 | |
270 | class PmdBoneDispName |
271 | { |
272 | public: |
273 | std::string bone_disp_name; |
274 | std::string bone_disp_name_english; |
275 | |
276 | void Read(std::istream *stream) |
277 | { |
278 | char buffer[50]; |
279 | stream->read(buffer, 50); |
280 | bone_disp_name = std::string(buffer); |
281 | bone_disp_name_english.clear(); |
282 | } |
283 | void ReadExpantion(std::istream *stream) |
284 | { |
285 | char buffer[50]; |
286 | stream->read(buffer, 50); |
287 | bone_disp_name_english = std::string(buffer); |
288 | } |
289 | }; |
290 | |
291 | class PmdBoneDisp |
292 | { |
293 | public: |
294 | uint16_t bone_index; |
295 | uint8_t bone_disp_index; |
296 | |
297 | void Read(std::istream *stream) |
298 | { |
299 | stream->read((char*) &bone_index, sizeof(uint16_t)); |
300 | stream->read((char*) &bone_disp_index, sizeof(uint8_t)); |
301 | } |
302 | }; |
303 | |
304 | enum class RigidBodyShape : uint8_t |
305 | { |
306 | Sphere = 0, |
307 | Box = 1, |
308 | Cpusel = 2 |
309 | }; |
310 | |
311 | enum class RigidBodyType : uint8_t |
312 | { |
313 | BoneConnected = 0, |
314 | Physics = 1, |
315 | ConnectedPhysics = 2 |
316 | }; |
317 | |
318 | class PmdRigidBody |
319 | { |
320 | public: |
321 | std::string name; |
322 | uint16_t related_bone_index; |
323 | uint8_t group_index; |
324 | uint16_t mask; |
325 | RigidBodyShape shape; |
326 | float size[3]; |
327 | float position[3]; |
328 | float orientation[3]; |
329 | float weight; |
330 | float linear_damping; |
331 | float anglar_damping; |
332 | float restitution; |
333 | float friction; |
334 | RigidBodyType rigid_type; |
335 | |
336 | void Read(std::istream *stream) |
337 | { |
338 | char buffer[20]; |
339 | stream->read(buffer, sizeof(char) * 20); |
340 | name = (std::string(buffer)); |
341 | stream->read((char*) &related_bone_index, sizeof(uint16_t)); |
342 | stream->read((char*) &group_index, sizeof(uint8_t)); |
343 | stream->read((char*) &mask, sizeof(uint16_t)); |
344 | stream->read((char*) &shape, sizeof(uint8_t)); |
345 | stream->read((char*) size, sizeof(float) * 3); |
346 | stream->read((char*) position, sizeof(float) * 3); |
347 | stream->read((char*) orientation, sizeof(float) * 3); |
348 | stream->read((char*) &weight, sizeof(float)); |
349 | stream->read((char*) &linear_damping, sizeof(float)); |
350 | stream->read((char*) &anglar_damping, sizeof(float)); |
351 | stream->read((char*) &restitution, sizeof(float)); |
352 | stream->read((char*) &friction, sizeof(float)); |
353 | stream->read((char*) &rigid_type, sizeof(char)); |
354 | } |
355 | }; |
356 | |
357 | class PmdConstraint |
358 | { |
359 | public: |
360 | std::string name; |
361 | uint32_t rigid_body_index_a; |
362 | uint32_t rigid_body_index_b; |
363 | float position[3]; |
364 | float orientation[3]; |
365 | float linear_lower_limit[3]; |
366 | float linear_upper_limit[3]; |
367 | float angular_lower_limit[3]; |
368 | float angular_upper_limit[3]; |
369 | float linear_stiffness[3]; |
370 | float angular_stiffness[3]; |
371 | |
372 | void Read(std::istream *stream) |
373 | { |
374 | char buffer[20]; |
375 | stream->read(buffer, 20); |
376 | name = std::string(buffer); |
377 | stream->read((char *) &rigid_body_index_a, sizeof(uint32_t)); |
378 | stream->read((char *) &rigid_body_index_b, sizeof(uint32_t)); |
379 | stream->read((char *) position, sizeof(float) * 3); |
380 | stream->read((char *) orientation, sizeof(float) * 3); |
381 | stream->read((char *) linear_lower_limit, sizeof(float) * 3); |
382 | stream->read((char *) linear_upper_limit, sizeof(float) * 3); |
383 | stream->read((char *) angular_lower_limit, sizeof(float) * 3); |
384 | stream->read((char *) angular_upper_limit, sizeof(float) * 3); |
385 | stream->read((char *) linear_stiffness, sizeof(float) * 3); |
386 | stream->read((char *) angular_stiffness, sizeof(float) * 3); |
387 | } |
388 | }; |
389 | |
390 | class PmdModel |
391 | { |
392 | public: |
393 | float version; |
394 | PmdHeader ; |
395 | std::vector<PmdVertex> vertices; |
396 | std::vector<uint16_t> indices; |
397 | std::vector<PmdMaterial> materials; |
398 | std::vector<PmdBone> bones; |
399 | std::vector<PmdIk> iks; |
400 | std::vector<PmdFace> faces; |
401 | std::vector<uint16_t> faces_indices; |
402 | std::vector<PmdBoneDispName> bone_disp_name; |
403 | std::vector<PmdBoneDisp> bone_disp; |
404 | std::vector<std::string> toon_filenames; |
405 | std::vector<PmdRigidBody> rigid_bodies; |
406 | std::vector<PmdConstraint> constraints; |
407 | |
408 | static std::unique_ptr<PmdModel> LoadFromFile(const char *filename) |
409 | { |
410 | std::ifstream stream(filename, std::ios::binary); |
411 | if (stream.fail()) |
412 | { |
413 | std::cerr << "could not open \"" << filename << "\"" << std::endl; |
414 | return nullptr; |
415 | } |
416 | auto result = LoadFromStream(&stream); |
417 | stream.close(); |
418 | return result; |
419 | } |
420 | |
421 | static std::unique_ptr<PmdModel> LoadFromStream(std::ifstream *stream) |
422 | { |
423 | auto result = mmd::make_unique<PmdModel>(); |
424 | char buffer[100]; |
425 | |
426 | // magic |
427 | char magic[3]; |
428 | stream->read(magic, 3); |
429 | if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd') |
430 | { |
431 | std::cerr << "invalid file" << std::endl; |
432 | return nullptr; |
433 | } |
434 | |
435 | // version |
436 | stream->read((char*) &(result->version), sizeof(float)); |
437 | if (result ->version != 1.0f) |
438 | { |
439 | std::cerr << "invalid version" << std::endl; |
440 | return nullptr; |
441 | } |
442 | |
443 | // header |
444 | result->header.Read(stream); |
445 | |
446 | // vertices |
447 | uint32_t vertex_num; |
448 | stream->read((char*) &vertex_num, sizeof(uint32_t)); |
449 | result->vertices.resize(vertex_num); |
450 | for (uint32_t i = 0; i < vertex_num; i++) |
451 | { |
452 | result->vertices[i].Read(stream); |
453 | } |
454 | |
455 | // indices |
456 | uint32_t index_num; |
457 | stream->read((char*) &index_num, sizeof(uint32_t)); |
458 | result->indices.resize(index_num); |
459 | for (uint32_t i = 0; i < index_num; i++) |
460 | { |
461 | stream->read((char*) &result->indices[i], sizeof(uint16_t)); |
462 | } |
463 | |
464 | // materials |
465 | uint32_t material_num; |
466 | stream->read((char*) &material_num, sizeof(uint32_t)); |
467 | result->materials.resize(material_num); |
468 | for (uint32_t i = 0; i < material_num; i++) |
469 | { |
470 | result->materials[i].Read(stream); |
471 | } |
472 | |
473 | // bones |
474 | uint16_t bone_num; |
475 | stream->read((char*) &bone_num, sizeof(uint16_t)); |
476 | result->bones.resize(bone_num); |
477 | for (uint32_t i = 0; i < bone_num; i++) |
478 | { |
479 | result->bones[i].Read(stream); |
480 | } |
481 | |
482 | // iks |
483 | uint16_t ik_num; |
484 | stream->read((char*) &ik_num, sizeof(uint16_t)); |
485 | result->iks.resize(ik_num); |
486 | for (uint32_t i = 0; i < ik_num; i++) |
487 | { |
488 | result->iks[i].Read(stream); |
489 | } |
490 | |
491 | // faces |
492 | uint16_t face_num; |
493 | stream->read((char*) &face_num, sizeof(uint16_t)); |
494 | result->faces.resize(face_num); |
495 | for (uint32_t i = 0; i < face_num; i++) |
496 | { |
497 | result->faces[i].Read(stream); |
498 | } |
499 | |
500 | // face frames |
501 | uint8_t face_frame_num; |
502 | stream->read((char*) &face_frame_num, sizeof(uint8_t)); |
503 | result->faces_indices.resize(face_frame_num); |
504 | for (uint32_t i = 0; i < face_frame_num; i++) |
505 | { |
506 | stream->read((char*) &result->faces_indices[i], sizeof(uint16_t)); |
507 | } |
508 | |
509 | // bone names |
510 | uint8_t bone_disp_num; |
511 | stream->read((char*) &bone_disp_num, sizeof(uint8_t)); |
512 | result->bone_disp_name.resize(bone_disp_num); |
513 | for (uint32_t i = 0; i < bone_disp_num; i++) |
514 | { |
515 | result->bone_disp_name[i].Read(stream); |
516 | } |
517 | |
518 | // bone frame |
519 | uint32_t bone_frame_num; |
520 | stream->read((char*) &bone_frame_num, sizeof(uint32_t)); |
521 | result->bone_disp.resize(bone_frame_num); |
522 | for (uint32_t i = 0; i < bone_frame_num; i++) |
523 | { |
524 | result->bone_disp[i].Read(stream); |
525 | } |
526 | |
527 | // english name |
528 | bool english; |
529 | stream->read((char*) &english, sizeof(char)); |
530 | if (english) |
531 | { |
532 | result->header.ReadExtension(stream); |
533 | for (uint32_t i = 0; i < bone_num; i++) |
534 | { |
535 | result->bones[i].ReadExpantion(stream); |
536 | } |
537 | for (uint32_t i = 0; i < face_num; i++) |
538 | { |
539 | if (result->faces[i].type == pmd::FaceCategory::Base) |
540 | { |
541 | continue; |
542 | } |
543 | result->faces[i].ReadExpantion(stream); |
544 | } |
545 | for (uint32_t i = 0; i < result->bone_disp_name.size(); i++) |
546 | { |
547 | result->bone_disp_name[i].ReadExpantion(stream); |
548 | } |
549 | } |
550 | |
551 | // toon textures |
552 | if (stream->peek() == std::ios::traits_type::eof()) |
553 | { |
554 | result->toon_filenames.clear(); |
555 | } |
556 | else { |
557 | result->toon_filenames.resize(10); |
558 | for (uint32_t i = 0; i < 10; i++) |
559 | { |
560 | stream->read(buffer, 100); |
561 | result->toon_filenames[i] = std::string(buffer); |
562 | } |
563 | } |
564 | |
565 | // physics |
566 | if (stream->peek() == std::ios::traits_type::eof()) |
567 | { |
568 | result->rigid_bodies.clear(); |
569 | result->constraints.clear(); |
570 | } |
571 | else { |
572 | uint32_t rigid_body_num; |
573 | stream->read((char*) &rigid_body_num, sizeof(uint32_t)); |
574 | result->rigid_bodies.resize(rigid_body_num); |
575 | for (uint32_t i = 0; i < rigid_body_num; i++) |
576 | { |
577 | result->rigid_bodies[i].Read(stream); |
578 | } |
579 | uint32_t constraint_num; |
580 | stream->read((char*) &constraint_num, sizeof(uint32_t)); |
581 | result->constraints.resize(constraint_num); |
582 | for (uint32_t i = 0; i < constraint_num; i++) |
583 | { |
584 | result->constraints[i].Read(stream); |
585 | } |
586 | } |
587 | |
588 | if (stream->peek() != std::ios::traits_type::eof()) |
589 | { |
590 | std::cerr << "there is unknown data" << std::endl; |
591 | } |
592 | |
593 | return result; |
594 | } |
595 | }; |
596 | } |
597 | |