Created
June 24, 2014 13:51
-
-
Save oguna/ecce8597c25d5eb5350a to your computer and use it in GitHub Desktop.
MMDのVMDモーションファイルのパーサー。C++11の機能を使っている
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright oguna 2014. | |
| // Distributed under the Boost Software License, Version 1.0. | |
| // (See accompanying file LICENSE_1_0.txt or copy at | |
| // http://www.boost.org/LICENSE_1_0.txt) | |
| #include <vector> | |
| #include <string> | |
| #include <memory> | |
| #include <iostream> | |
| #include <fstream> | |
| namespace vmd | |
| { | |
| /// ボーンフレーム | |
| class VmdBoneFrame | |
| { | |
| public: | |
| /// ボーン名 | |
| std::string name; | |
| /// フレーム番号 | |
| int frame; | |
| /// 位置 | |
| float position[3]; | |
| /// 回転 | |
| float orientation[4]; | |
| /// 補間曲線 | |
| char interpolation[4][4][4]; | |
| void Read(std::istream* stream) | |
| { | |
| char buffer[15]; | |
| stream->read((char*) buffer, sizeof(char)*15); | |
| name = std::string(buffer); | |
| stream->read((char*) &frame, sizeof(int)); | |
| stream->read((char*) position, sizeof(float)*3); | |
| stream->read((char*) orientation, sizeof(float)*4); | |
| stream->read((char*) interpolation, sizeof(char) * 4 * 4 * 4); | |
| } | |
| }; | |
| /// 表情フレーム | |
| class VmdFaceFrame | |
| { | |
| public: | |
| /// 表情名 | |
| std::string face_name; | |
| /// 表情の重み | |
| float weight; | |
| /// フレーム番号 | |
| uint32_t frame; | |
| void Read(std::istream* stream) | |
| { | |
| char buffer[15]; | |
| stream->read((char*) &buffer, sizeof(char) * 15); | |
| face_name = std::string(buffer); | |
| stream->read((char*) &frame, sizeof(int)); | |
| stream->read((char*) &weight, sizeof(float)); | |
| } | |
| }; | |
| /// カメラフレーム | |
| class VmdCameraFrame | |
| { | |
| public: | |
| /// フレーム番号 | |
| int frame; | |
| /// 距離 | |
| float distance; | |
| /// 位置 | |
| float position[3]; | |
| /// 回転 | |
| float orientation[3]; | |
| /// 補間曲線 | |
| char interpolation[6][4]; | |
| /// 視野角 | |
| float angle; | |
| /// 不明データ | |
| char unknown[3]; | |
| void Read(std::istream *stream) | |
| { | |
| stream->read((char*) &frame, sizeof(int)); | |
| stream->read((char*) &distance, sizeof(float)); | |
| stream->read((char*) position, sizeof(float) * 3); | |
| stream->read((char*) orientation, sizeof(float) * 3); | |
| stream->read((char*) interpolation, sizeof(char) * 24); | |
| stream->read((char*) &angle, sizeof(float)); | |
| stream->read((char*) unknown, sizeof(char) * 3); | |
| } | |
| }; | |
| /// ライトフレーム | |
| class VmdLightFrame | |
| { | |
| public: | |
| /// フレーム番号 | |
| int frame; | |
| /// 色 | |
| float color[3]; | |
| /// 位置 | |
| float position[3]; | |
| void Read(std::istream* stream) | |
| { | |
| stream->read((char*) &frame, sizeof(int)); | |
| stream->read((char*) color, sizeof(float) * 3); | |
| stream->read((char*) position, sizeof(float) * 3); | |
| } | |
| }; | |
| /// IKの有効無効 | |
| class VmdIkEnable | |
| { | |
| public: | |
| std::string ik_name; | |
| bool enable; | |
| }; | |
| /// IKフレーム | |
| class VmdIkFrame | |
| { | |
| public: | |
| int frame; | |
| bool display; | |
| std::vector<VmdIkEnable> ik_enable; | |
| void Read(std::istream *stream) | |
| { | |
| char buffer[20]; | |
| stream->read((char*) &frame, sizeof(int)); | |
| stream->read((char*) &display, sizeof(uint8_t)); | |
| int ik_count; | |
| stream->read((char*) &ik_count, sizeof(int)); | |
| ik_enable.resize(ik_count); | |
| for (int i = 0; i < ik_count; i++) | |
| { | |
| stream->read(buffer, 20); | |
| ik_enable[i].ik_name = std::string(buffer); | |
| stream->read((char*) &ik_enable[i].enable, sizeof(uint8_t)); | |
| } | |
| } | |
| }; | |
| /// VMDモーション | |
| class VmdMotion | |
| { | |
| public: | |
| /// モデル名 | |
| std::string model_name; | |
| /// バージョン | |
| int version; | |
| /// ボーンフレーム | |
| std::vector<VmdBoneFrame> bone_frames; | |
| /// 表情フレーム | |
| std::vector<VmdFaceFrame> face_frames; | |
| /// カメラフレーム | |
| std::vector<VmdCameraFrame> camera_frames; | |
| /// ライトフレーム | |
| std::vector<VmdLightFrame> light_frames; | |
| /// IKフレーム | |
| std::vector<VmdIkFrame> ik_frames; | |
| static std::unique_ptr<VmdMotion> LoadFromFile(char const *filename) | |
| { | |
| std::ifstream stream(filename, std::ios::binary); | |
| auto result = LoadFromStream(&stream); | |
| stream.close(); | |
| return result; | |
| } | |
| static std::unique_ptr<VmdMotion> LoadFromStream(std::ifstream *stream) | |
| { | |
| char buffer[30]; | |
| auto result = std::make_unique<VmdMotion>(); | |
| // magic and version | |
| stream->read((char*) buffer, 30); | |
| if (strncmp(buffer, "Vocaloid Motion Data", 20)) | |
| { | |
| std::cerr << "invalid vmd file." << std::endl; | |
| return nullptr; | |
| } | |
| result->version = std::atoi(buffer + 20); | |
| // name | |
| stream->read(buffer, 20); | |
| result->model_name = std::string(buffer); | |
| // bone frames | |
| int bone_frame_num; | |
| stream->read((char*) &bone_frame_num, sizeof(int)); | |
| result->bone_frames.resize(bone_frame_num); | |
| for (uint16_t i = 0; i < bone_frame_num; i++) | |
| { | |
| result->bone_frames[i].Read(stream); | |
| } | |
| // face frames | |
| int face_frame_num; | |
| stream->read((char*) &face_frame_num, sizeof(int)); | |
| result->face_frames.resize(face_frame_num); | |
| for (int i = 0; i < face_frame_num; i++) | |
| { | |
| result->face_frames[i].Read(stream); | |
| } | |
| // camera frames | |
| int camera_frame_num; | |
| stream->read((char*) &camera_frame_num, sizeof(int)); | |
| result->camera_frames.resize(camera_frame_num); | |
| for (int i = 0; i < camera_frame_num; i++) | |
| { | |
| result->camera_frames[i].Read(stream); | |
| } | |
| // light frames | |
| int light_frame_num; | |
| stream->read((char*) &light_frame_num, sizeof(int)); | |
| result->light_frames.resize(light_frame_num); | |
| for (int i = 0; i < light_frame_num; i++) | |
| { | |
| result->light_frames[i].Read(stream); | |
| } | |
| // unknown2 | |
| stream->read(buffer, 4); | |
| // ik frames | |
| if (!stream->eof()) | |
| { | |
| int ik_num; | |
| stream->read((char*) &ik_num, sizeof(int)); | |
| result->ik_frames.resize(ik_num); | |
| for (int i = 0; i < ik_num; i++) | |
| { | |
| result->ik_frames[i].Read(stream); | |
| } | |
| } | |
| if (!stream->eof()) | |
| { | |
| std::cerr << "vmd stream has unknown data." << std::endl; | |
| } | |
| return result; | |
| } | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment