/** *** BVHファイルの読み込み・描画クラス *** Copyright (c) 2004, Masaki OSHITA **/ #include #include #ifdef WIN32 #include #endif #include #include "mogl.h" #include "BVH.h" // コントラクタ BVH::BVH() { motion = NULL; Clear(); } // コントラクタ BVH::BVH( const char * bvh_file_name ) { motion = NULL; Clear(); Load( bvh_file_name ); } // デストラクタ BVH::~BVH() { Clear(); } // 全情報のクリア void BVH::Clear() { int i; for ( i=0; i joint_stack; Joint * joint = NULL; Joint * new_joint = NULL; bool is_site = false; double x, y ,z; int i, j; // 初期化 Clear(); // ファイルの情報(ファイル名・動作名)の設定 file_name = bvh_file_name; const char * mn_first = bvh_file_name; const char * mn_last = bvh_file_name + strlen( bvh_file_name ); if ( strrchr( bvh_file_name, '\\' ) != NULL ) mn_first = strrchr( bvh_file_name, '\\' ) + 1; else if ( strrchr( bvh_file_name, '/' ) != NULL ) mn_first = strrchr( bvh_file_name, '/' ) + 1; if ( strrchr( bvh_file_name, '.' ) != NULL ) mn_last = strrchr( bvh_file_name, '.' ); if ( mn_last < mn_first ) mn_last = bvh_file_name + strlen( bvh_file_name ); motion_name.assign( mn_first, mn_last ); // ファイルのオープン file.open( bvh_file_name, ios::in ); if ( file.is_open() == 0 ) return; // ファイルが開けなかったら終了 // 階層情報の読み込み while ( ! file.eof() ) { // ファイルの最後まできてしまったら異常終了 if ( file.eof() ) goto bvh_error; // 1行読み込み、先頭の単語を取得 file.getline( line, BUFFER_LENGTH ); token = strtok( line, separater ); // 空行の場合は次の行へ if ( token == NULL ) continue; // 関節ブロックの開始 if ( strcmp( token, "{" ) == 0 ) { // 現在の関節をスタックに積む joint_stack.push_back( joint ); joint = new_joint; continue; } // 関節ブロックの終了 if ( strcmp( token, "}" ) == 0 ) { // 現在の関節をスタックから取り出す joint = joint_stack.back(); joint_stack.pop_back(); is_site = false; continue; } // 関節情報の開始 if ( ( strcmp( token, "ROOT" ) == 0 ) || ( strcmp( token, "JOINT" ) == 0 ) ) { // 関節データの作成 new_joint = new Joint(); new_joint->index = joints.size(); new_joint->parent = joint; new_joint->has_site = false; new_joint->offset[0] = 0.0; new_joint->offset[1] = 0.0; new_joint->offset[2] = 0.0; new_joint->site[0] = 0.0; new_joint->site[1] = 0.0; new_joint->site[2] = 0.0; joints.push_back( new_joint ); if ( joint ) joint->children.push_back( new_joint ); // 関節名の読み込み token = strtok( NULL, "" ); while ( *token == ' ' ) token ++; new_joint->name = token; // インデックスへ追加 joint_index[ new_joint->name ] = new_joint; continue; } // 末端情報の開始 if ( ( strcmp( token, "End" ) == 0 ) ) { new_joint = joint; is_site = true; continue; } // 関節のオフセット or 末端位置の情報 if ( strcmp( token, "OFFSET" ) == 0 ) { // 座標値を読み込み token = strtok( NULL, separater ); x = token ? atof( token ) : 0.0; token = strtok( NULL, separater ); y = token ? atof( token ) : 0.0; token = strtok( NULL, separater ); z = token ? atof( token ) : 0.0; // 関節のオフセットに座標値を設定 if ( is_site ) { joint->has_site = true; joint->site[0] = x; joint->site[1] = y; joint->site[2] = z; } else // 末端位置に座標値を設定 { joint->offset[0] = x; joint->offset[1] = y; joint->offset[2] = z; } continue; } // 関節のチャンネル情報 if ( strcmp( token, "CHANNELS" ) == 0 ) { // チャンネル数を読み込み token = strtok( NULL, separater ); joint->channels.resize( token ? atoi( token ) : 0 ); // チャンネル情報を読み込み for ( i=0; ichannels.size(); i++ ) { // チャンネルの作成 Channel * channel = new Channel(); channel->joint = joint; channel->index = channels.size(); channels.push_back( channel ); joint->channels[ i ] = channel; // チャンネルの種類の判定 token = strtok( NULL, separater ); if ( strcmp( token, "Xrotation" ) == 0 ) channel->type = X_ROTATION; else if ( strcmp( token, "Yrotation" ) == 0 ) channel->type = Y_ROTATION; else if ( strcmp( token, "Zrotation" ) == 0 ) channel->type = Z_ROTATION; else if ( strcmp( token, "Xposition" ) == 0 ) channel->type = X_POSITION; else if ( strcmp( token, "Yposition" ) == 0 ) channel->type = Y_POSITION; else if ( strcmp( token, "Zposition" ) == 0 ) channel->type = Z_POSITION; } } // Motionデータのセクションへ移る if ( strcmp( token, "MOTION" ) == 0 ) break; } // モーション情報の読み込み file.getline( line, BUFFER_LENGTH ); token = strtok( line, separater ); if ( strcmp( token, "Frames" ) != 0 ) goto bvh_error; token = strtok( NULL, separater ); if ( token == NULL ) goto bvh_error; num_frame = atoi( token ); file.getline( line, BUFFER_LENGTH ); token = strtok( line, ":" ); if ( strcmp( token, "Frame Time" ) != 0 ) goto bvh_error; token = strtok( NULL, separater ); if ( token == NULL ) goto bvh_error; interval = atof( token ); num_channel = channels.size(); motion = new double[ num_frame * num_channel ]; // モーションデータの読み込み for ( i=0; iparent == NULL ) { glTranslatef( data[ 0 ] * scale, data[ 1 ] * scale, data[ 2 ] * scale ); } // 子関節の場合は親関節からの平行移動を適用 else { glTranslatef( joint->offset[ 0 ] * scale, joint->offset[ 1 ] * scale, joint->offset[ 2 ] * scale ); } // 親関節からの回転を適用(ルート関節の場合はワールド座標からの回転) int i, j; for ( i=0; ichannels.size(); i++ ) { Channel * channel = joint->channels[ i ]; if ( channel->type == X_ROTATION ) glRotatef( data[ channel->index ], 1.0f, 0.0f, 0.0f ); else if ( channel->type == Y_ROTATION ) glRotatef( data[ channel->index ], 0.0f, 1.0f, 0.0f ); else if ( channel->type == Z_ROTATION ) glRotatef( data[ channel->index ], 0.0f, 0.0f, 1.0f ); } // リンクを描画 // 関節座標系の原点から末端点へのリンクを描画 if ( joint->children.size() == 0 ) { RenderBone( 0.0f, 0.0f, 0.0f, joint->site[ 0 ] * scale, joint->site[ 1 ] * scale, joint->site[ 2 ] * scale ); } // 関節座標系の原点から次の関節への接続位置へのリンクを描画 if ( joint->children.size() == 1 ) { Joint * child = joint->children[ 0 ]; RenderBone( 0.0f, 0.0f, 0.0f, child->offset[ 0 ] * scale, child->offset[ 1 ] * scale, child->offset[ 2 ] * scale ); } // 全関節への接続位置への中心点から各関節への接続位置へ円柱を描画 if ( joint->children.size() > 1 ) { // 原点と全関節への接続位置への中心点を計算 float center[ 3 ] = { 0.0f, 0.0f, 0.0f }; for ( i=0; ichildren.size(); i++ ) { Joint * child = joint->children[ i ]; center[ 0 ] += child->offset[ 0 ]; center[ 1 ] += child->offset[ 1 ]; center[ 2 ] += child->offset[ 2 ]; } center[ 0 ] /= joint->children.size() + 1; center[ 1 ] /= joint->children.size() + 1; center[ 2 ] /= joint->children.size() + 1; // 原点から中心点へのリンクを描画 RenderBone( 0.0f, 0.0f, 0.0f, center[ 0 ] * scale, center[ 1 ] * scale, center[ 2 ] * scale ); // 中心点から次の関節への接続位置へのリンクを描画 for ( i=0; ichildren.size(); i++ ) { Joint * child = joint->children[ i ]; RenderBone( center[ 0 ] * scale, center[ 1 ] * scale, center[ 2 ] * scale, child->offset[ 0 ] * scale, child->offset[ 1 ] * scale, child->offset[ 2 ] * scale ); } } // 子関節に対して再帰呼び出し for ( i=0; ichildren.size(); i++ ) { RenderFigure( joint->children[ i ], data, scale ); } glPopMatrix(); } // BVH骨格の1本のリンクを描画(クラス関数) void BVH::RenderBone( float x0, float y0, float z0, float x1, float y1, float z1 ) { // 2点を結ぶ円柱を描画 modgSolidPipe( x0, y0, z0, x1, y1, z1, 0.01, 8, 3 ); } // End of BVH.cpp