Skip to content

Instantly share code, notes, and snippets.

@oguna
Created June 24, 2014 13:51
Show Gist options
  • Select an option

  • Save oguna/ecce8597c25d5eb5350a to your computer and use it in GitHub Desktop.

Select an option

Save oguna/ecce8597c25d5eb5350a to your computer and use it in GitHub Desktop.
MMDのVMDモーションファイルのパーサー。C++11の機能を使っている
// 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