818 lines
20 KiB
C++
818 lines
20 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <Max.h>
|
|
#include <istdplug.h>
|
|
|
|
#include "asf_data.h"
|
|
#include "read_asf.h"
|
|
#include "exception.h"
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASF_Lexer::ASF_Lexer
|
|
//----------------------------------------------------------------------------
|
|
|
|
ASF_Lexer::ASF_Lexer
|
|
(
|
|
const char * file_name
|
|
):
|
|
Input_file ( file_name, "r" )
|
|
{
|
|
Current_char = tolower ( fgetc ( Input_file.fp ) );
|
|
advance ();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASF_Lexer::skip_whitespace
|
|
//----------------------------------------------------------------------------
|
|
// Skip whitespace and comments, leaving the Current_char pointing to the
|
|
// first non-whitespace character in the input stream.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void ASF_Lexer::skip_whitespace ()
|
|
{
|
|
while (1)
|
|
{
|
|
if ( Current_char == '#' ) // Strip out comments
|
|
{
|
|
while ( Current_char != '\n' && Current_char != EOF )
|
|
Current_char = tolower ( fgetc ( Input_file.fp ) );
|
|
}
|
|
else if ( (isspace ( Current_char ) && Current_char != '\n') ||
|
|
Current_char == ',' ||
|
|
Current_char == '(' ||
|
|
Current_char == ')' )
|
|
{
|
|
Current_char = tolower ( fgetc ( Input_file.fp ) );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASF_Lexer::advance
|
|
//----------------------------------------------------------------------------
|
|
// Advance to the next token in the input stream.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void ASF_Lexer::advance ()
|
|
{
|
|
skip_whitespace ();
|
|
|
|
if ( Current_char == EOF )
|
|
{
|
|
Current_type = EOF_MARKER;
|
|
strcpy ( Current_text, "<end of file>" );
|
|
return;
|
|
}
|
|
|
|
if ( Current_char == '\n' )
|
|
{
|
|
Current_type = NEWLINE;
|
|
strcpy ( Current_text, "<newline>" );
|
|
Current_char = tolower ( fgetc ( Input_file.fp ) );
|
|
return;
|
|
}
|
|
|
|
Current_type = TOKEN;
|
|
|
|
// Read characters into the token text buffer.
|
|
|
|
int i = 0;
|
|
|
|
while ( ! isspace (Current_char) &&
|
|
Current_char != '#' &&
|
|
Current_char != ',' &&
|
|
Current_char != '(' &&
|
|
Current_char != ')' &&
|
|
Current_char != EOF )
|
|
{
|
|
if ( i >= (MAX_TOKEN_LENGTH - 1) )
|
|
{
|
|
// Abort -- maximum token length exceeded.
|
|
|
|
throw Parse_Error ( "Maximum token length exceeded." );
|
|
}
|
|
|
|
Current_text [i] = Current_char;
|
|
++ i;
|
|
|
|
Current_char = tolower ( fgetc ( Input_file.fp ) );
|
|
}
|
|
|
|
Current_text [i] = '\0';
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::Skeleton_Class
|
|
//----------------------------------------------------------------------------
|
|
|
|
Skeleton_Class::Skeleton_Class
|
|
(
|
|
const char * file_name,
|
|
ImpInterface * iface,
|
|
Interface * gi
|
|
) :
|
|
Angle_multiplier (DEGREES_TO_RADIANS),
|
|
Length_multiplier (1.0f),
|
|
First_bone (NULL),
|
|
Import_interface (iface),
|
|
Max_interface (gi)
|
|
{
|
|
ASF_Lexer lexer ( file_name );
|
|
|
|
parse_units_block ( lexer );
|
|
parse_root_block ( lexer );
|
|
parse_bonedata_block ( lexer );
|
|
parse_hierarchy_block ( lexer );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::~Skeleton_Class
|
|
//----------------------------------------------------------------------------
|
|
|
|
Skeleton_Class::~Skeleton_Class ()
|
|
{
|
|
Bone_Class * p = First_bone;
|
|
|
|
while ( p != NULL )
|
|
{
|
|
Bone_Class * delete_p = p;
|
|
p = p->next_bone ();
|
|
|
|
delete delete_p;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_units_block
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_units_block ( ASF_Lexer & lexer )
|
|
{
|
|
skip_unrecognized_blocks ( lexer );
|
|
|
|
match_token ( lexer, ":units" );
|
|
match_newline ( lexer );
|
|
|
|
BOOL mass_defined = FALSE;
|
|
BOOL length_defined = FALSE;
|
|
BOOL angle_defined = FALSE;
|
|
|
|
while (1)
|
|
{
|
|
verify_token ( lexer );
|
|
|
|
if ( strcmp ( lexer.text (), "mass" ) == 0 )
|
|
{
|
|
if ( mass_defined )
|
|
throw Parse_Error ( "Multiple mass definitions." );
|
|
|
|
lexer.advance ();
|
|
skip_token ( lexer ); // Ignore the mass definition.
|
|
match_newline ( lexer );
|
|
|
|
mass_defined = TRUE;
|
|
}
|
|
else if ( strcmp ( lexer.text (), "length" ) == 0 )
|
|
{
|
|
if ( length_defined )
|
|
throw Parse_Error ( "Multiple length definitions." );
|
|
|
|
lexer.advance ();
|
|
verify_token ( lexer );
|
|
Length_multiplier = 1.0f / float_token ( lexer );
|
|
match_newline ( lexer );
|
|
|
|
length_defined = TRUE;
|
|
}
|
|
else if ( strcmp ( lexer.text (), "angle" ) == 0 )
|
|
{
|
|
if ( angle_defined )
|
|
throw Parse_Error ( "Multiple angle definitions." );
|
|
|
|
lexer.advance ();
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "deg" ) == 0 )
|
|
Angle_multiplier = DEGREES_TO_RADIANS;
|
|
else if ( strcmp ( lexer.text (), "rad" ) == 0 )
|
|
Angle_multiplier = 1.0f;
|
|
else
|
|
throw Parse_Error
|
|
( "\"deg\" or \"rad\" expected after angle keyword." );
|
|
|
|
lexer.advance ();
|
|
match_newline ( lexer );
|
|
|
|
angle_defined = TRUE;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_root_block
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_root_block ( ASF_Lexer & lexer )
|
|
{
|
|
skip_unrecognized_blocks ( lexer );
|
|
|
|
match_token ( lexer, ":root" );
|
|
match_newline ( lexer );
|
|
|
|
// Create a root bone.
|
|
|
|
Bone_Class * new_bone = new Bone_Class;
|
|
new_bone->set_name ( "root" );
|
|
|
|
// The rotation order for orientation offset.
|
|
|
|
match_token ( lexer, "axis" );
|
|
skip_token ( lexer ); // &&& get rotation order for orientation offset.
|
|
match_newline ( lexer );
|
|
|
|
// The order of transformations for root.
|
|
|
|
match_token ( lexer, "order" );
|
|
for ( int i = 0; i < 6; ++ i )
|
|
{
|
|
verify_token ( lexer );
|
|
|
|
if ( strcmp ( lexer.text (), "rx" ) == 0 )
|
|
new_bone->add_axis ( ROTATE_X );
|
|
else if ( strcmp ( lexer.text (), "ry" ) == 0 )
|
|
new_bone->add_axis ( ROTATE_Y );
|
|
else if ( strcmp ( lexer.text (), "rz" ) == 0 )
|
|
new_bone->add_axis ( ROTATE_Z );
|
|
else if ( strcmp ( lexer.text (), "tx" ) == 0 )
|
|
new_bone->add_axis ( TRANSLATE_X );
|
|
else if ( strcmp ( lexer.text (), "ty" ) == 0 )
|
|
new_bone->add_axis ( TRANSLATE_Y );
|
|
else if ( strcmp ( lexer.text (), "tz" ) == 0 )
|
|
new_bone->add_axis ( TRANSLATE_Z );
|
|
else
|
|
throw Parse_Error ( "Unrecognized order token in :root." );
|
|
|
|
lexer.advance ();
|
|
}
|
|
match_newline ( lexer );
|
|
|
|
// Translation data for root node.
|
|
|
|
match_token ( lexer, "position" );
|
|
skip_token ( lexer ); // &&&
|
|
skip_token ( lexer ); // &&&
|
|
skip_token ( lexer ); // &&&
|
|
match_newline ( lexer );
|
|
|
|
// Rotation data to orient the skeleton.
|
|
|
|
match_token ( lexer, "orientation" );
|
|
float rot0 = float_token ( lexer ) * Angle_multiplier;
|
|
float rot1 = float_token ( lexer ) * Angle_multiplier;
|
|
float rot2 = float_token ( lexer ) * Angle_multiplier;
|
|
match_newline ( lexer );
|
|
|
|
Matrix3 axis_tm;
|
|
axis_tm.IdentityMatrix ();
|
|
axis_tm.RotateX ( rot0 );
|
|
axis_tm.RotateY ( rot1 );
|
|
axis_tm.RotateZ ( rot2 );
|
|
new_bone->set_axis_tm ( axis_tm );
|
|
|
|
new_bone->set_direction ( Point3 (0,0,0) );
|
|
new_bone->set_length ( 0.0f );
|
|
|
|
add_bone_to_list ( new_bone );
|
|
new_bone->create_node ( Import_interface, Max_interface );
|
|
|
|
// Add an AppData chunk to the root node to indicate how much to scale
|
|
// its position keys.
|
|
Position_Key_Scale_Chunk * data_p = (Position_Key_Scale_Chunk *)
|
|
malloc ( sizeof (Position_Key_Scale_Chunk) );
|
|
|
|
data_p->Position_Key_Scale = Length_multiplier;
|
|
|
|
new_bone->add_app_data ( 2, data_p, sizeof (Position_Key_Scale_Chunk) );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_bonedata_block
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_bonedata_block ( ASF_Lexer & lexer )
|
|
{
|
|
skip_unrecognized_blocks ( lexer );
|
|
|
|
match_token ( lexer, ":bonedata" );
|
|
match_newline ( lexer );
|
|
|
|
// Parse bone definition blocks.
|
|
|
|
while (1)
|
|
{
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "begin" ) == 0 )
|
|
{
|
|
parse_bone ( lexer );
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_hierarchy_block
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_hierarchy_block ( ASF_Lexer & lexer )
|
|
{
|
|
skip_unrecognized_blocks ( lexer );
|
|
|
|
match_token ( lexer, ":hierarchy" );
|
|
match_newline ( lexer );
|
|
|
|
match_token ( lexer, "begin" );
|
|
match_newline ( lexer );
|
|
|
|
while (1)
|
|
{
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "end" ) == 0 )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
parse_hierarchy_line ( lexer );
|
|
}
|
|
}
|
|
|
|
lexer.advance ();
|
|
match_newline ( lexer );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_hierarchy_line
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_hierarchy_line ( ASF_Lexer & lexer )
|
|
{
|
|
verify_token ( lexer );
|
|
Bone_Class * parent_bone = find_bone ( lexer.text () );
|
|
if ( parent_bone == NULL )
|
|
throw Parse_Error ( "Undefined parent bone." );
|
|
lexer.advance ();
|
|
|
|
while ( lexer.type () == TOKEN )
|
|
{
|
|
Bone_Class * child_bone = find_bone ( lexer.text () );
|
|
if ( child_bone == NULL )
|
|
throw Parse_Error ( "Undefined child bone." );
|
|
|
|
child_bone->set_parent ( parent_bone );
|
|
|
|
lexer.advance ();
|
|
}
|
|
|
|
match_newline ( lexer );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::find_bone
|
|
//----------------------------------------------------------------------------
|
|
|
|
Bone_Class * Skeleton_Class::find_bone ( const char * name )
|
|
{
|
|
Bone_Class * p = First_bone;
|
|
|
|
while ( p != NULL )
|
|
{
|
|
if ( strcmp ( name, p->name () ) == 0 )
|
|
break;
|
|
|
|
p = p->next_bone ();
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// lh_to_rh
|
|
//----------------------------------------------------------------------------
|
|
|
|
static Point3 lh_to_rh ( Point3 point )
|
|
{
|
|
Point3 new_point;
|
|
|
|
new_point.x = point.x;
|
|
new_point.y = -point.z;
|
|
new_point.z = point.y;
|
|
|
|
return new_point;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::parse_bone
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::parse_bone ( ASF_Lexer & lexer )
|
|
{
|
|
match_token ( lexer, "begin" );
|
|
match_newline ( lexer );
|
|
|
|
// Create a new bone object.
|
|
|
|
Bone_Class * new_bone = new Bone_Class;
|
|
|
|
// Optional ID number.
|
|
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "id" ) == 0 )
|
|
{
|
|
lexer.advance ();
|
|
skip_token ( lexer ); // Ignore the bone ID number for now.
|
|
match_newline ( lexer );
|
|
}
|
|
|
|
// Name.
|
|
|
|
match_token ( lexer, "name" );
|
|
verify_token ( lexer );
|
|
new_bone->set_name ( lexer.text () );
|
|
lexer.advance ();
|
|
match_newline ( lexer );
|
|
|
|
// Direction vector.
|
|
|
|
match_token ( lexer, "direction" );
|
|
Point3 direction;
|
|
direction.x = float_token ( lexer );
|
|
direction.y = float_token ( lexer );
|
|
direction.z = float_token ( lexer );
|
|
new_bone->set_direction ( direction );
|
|
match_newline ( lexer );
|
|
|
|
// Length.
|
|
|
|
match_token ( lexer, "length" );
|
|
new_bone->set_length ( float_token ( lexer ) * Length_multiplier / (float)GetMasterScale(UNITS_INCHES));
|
|
match_newline ( lexer );
|
|
|
|
// Rotation axis in world coordinates, with order of rotations.
|
|
|
|
match_token ( lexer, "axis" );
|
|
float rot0 = float_token ( lexer ) * Angle_multiplier;
|
|
float rot1 = float_token ( lexer ) * Angle_multiplier;
|
|
float rot2 = float_token ( lexer ) * Angle_multiplier;
|
|
|
|
// &&& Ultimately this should handle any order of rotations.
|
|
match_token ( lexer, "xyz" );
|
|
|
|
match_newline ( lexer );
|
|
|
|
Matrix3 axis_tm;
|
|
axis_tm.IdentityMatrix ();
|
|
axis_tm.RotateX ( rot0 );
|
|
axis_tm.RotateY ( rot1 );
|
|
axis_tm.RotateZ ( rot2 );
|
|
new_bone->set_axis_tm ( axis_tm );
|
|
|
|
// Optional mass of skinbody associated with this bone.
|
|
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "bodymass" ) == 0 )
|
|
{
|
|
lexer.advance ();
|
|
skip_token ( lexer ); // Ignore the bodymass.
|
|
match_newline ( lexer );
|
|
}
|
|
|
|
// Optional position of center of mass along the bone.
|
|
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "cofmass" ) == 0 )
|
|
{
|
|
lexer.advance ();
|
|
skip_token ( lexer ); // Ignore the center of mass position.
|
|
match_newline ( lexer );
|
|
}
|
|
|
|
// Optional degrees of freedom.
|
|
|
|
verify_token ( lexer );
|
|
if ( strcmp ( lexer.text (), "dof" ) == 0 )
|
|
{
|
|
lexer.advance ();
|
|
|
|
if ( lexer.type () == TOKEN && strcmp ( lexer.text (), "rx" ) == 0 )
|
|
{
|
|
new_bone->add_axis ( ROTATE_X );
|
|
lexer.advance ();
|
|
}
|
|
|
|
if ( lexer.type () == TOKEN && strcmp ( lexer.text (), "ry" ) == 0 )
|
|
{
|
|
new_bone->add_axis ( ROTATE_Y );
|
|
lexer.advance ();
|
|
}
|
|
|
|
if ( lexer.type () == TOKEN && strcmp ( lexer.text (), "rz" ) == 0 )
|
|
{
|
|
new_bone->add_axis ( ROTATE_Z );
|
|
lexer.advance ();
|
|
}
|
|
|
|
if ( lexer.type () == TOKEN && strcmp ( lexer.text (), "l" ) == 0 )
|
|
{
|
|
new_bone->add_axis ( TRANSLATE_LENGTH );
|
|
lexer.advance ();
|
|
}
|
|
|
|
match_newline ( lexer );
|
|
|
|
// Limits for the given degrees of freedom.
|
|
|
|
match_token ( lexer, "limits" );
|
|
|
|
// &&&
|
|
|
|
while ( strcmp ( lexer.text (), "end" ) != 0 )
|
|
lexer.advance ();
|
|
}
|
|
|
|
match_token ( lexer, "end" );
|
|
match_newline ( lexer );
|
|
|
|
// Add the bone to the list of bones.
|
|
|
|
add_bone_to_list ( new_bone );
|
|
|
|
new_bone->create_node ( Import_interface, Max_interface );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::skip_unrecognized_blocks
|
|
//----------------------------------------------------------------------------
|
|
// It is assumed that the current lexeme is the first on a line.
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::skip_unrecognized_blocks
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
while (1)
|
|
{
|
|
if ( lexer.type () == EOF_MARKER )
|
|
break;
|
|
if ( strcmp ( lexer.text (), ":units" ) == 0 )
|
|
break;
|
|
if ( strcmp ( lexer.text (), ":root" ) == 0 )
|
|
break;
|
|
if ( strcmp ( lexer.text (), ":bonedata" ) == 0 )
|
|
break;
|
|
if ( strcmp ( lexer.text (), ":hierarchy" ) == 0 )
|
|
break;
|
|
|
|
skip_to_next_line ( lexer );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::skip_to_next_line
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::skip_to_next_line
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
while ( lexer.type () != NEWLINE &&
|
|
lexer.type () != EOF_MARKER )
|
|
lexer.advance ();
|
|
|
|
if ( lexer.type () == NEWLINE )
|
|
lexer.advance ();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::match_newline
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::match_newline
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
char message_buffer [ 512 ];
|
|
|
|
if ( lexer.type () != NEWLINE )
|
|
{
|
|
sprintf ( message_buffer, "Expected newline; found \"%s\" instead.",
|
|
lexer.text () );
|
|
throw Parse_Error ( message_buffer );
|
|
}
|
|
|
|
lexer.advance ();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::verify_token
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::verify_token
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
char message_buffer [ 512 ];
|
|
|
|
if ( lexer.type () != TOKEN )
|
|
{
|
|
sprintf ( message_buffer, "Expected token; found \"%s\" instead.",
|
|
lexer.text () );
|
|
throw Parse_Error ( message_buffer );
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::skip_token
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::skip_token
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
verify_token ( lexer );
|
|
lexer.advance ();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::float_token
|
|
//----------------------------------------------------------------------------
|
|
|
|
float Skeleton_Class::float_token
|
|
(
|
|
ASF_Lexer & lexer
|
|
)
|
|
{
|
|
verify_token ( lexer );
|
|
float value = (float) strtod ( lexer.text (), NULL );
|
|
lexer.advance ();
|
|
return value;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::match_token
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::match_token
|
|
(
|
|
ASF_Lexer & lexer,
|
|
const char * token_text
|
|
)
|
|
{
|
|
char message_buffer [ 512 ];
|
|
|
|
verify_token ( lexer );
|
|
|
|
if ( strcmp ( lexer.text (), token_text ) != 0 )
|
|
{
|
|
sprintf ( message_buffer, "Expected \"%s\"; found \"%s\" instead.",
|
|
token_text, lexer.text () );
|
|
throw Parse_Error ( message_buffer );
|
|
}
|
|
|
|
lexer.advance ();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Skeleton_Class::add_bone_to_list
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Skeleton_Class::add_bone_to_list
|
|
(
|
|
Bone_Class * new_bone
|
|
)
|
|
{
|
|
new_bone->set_next_bone ( First_bone );
|
|
First_bone = new_bone;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Bone_Class::create_node
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Bone_Class::create_node
|
|
(
|
|
ImpInterface * import_interface,
|
|
Interface * max_interface
|
|
)
|
|
{
|
|
Node = import_interface->CreateNode ();
|
|
Node->SetName ( Name );
|
|
|
|
// Create a box object.
|
|
|
|
GeomObject * obj = (GeomObject *) max_interface->CreateInstance
|
|
( GEOMOBJECT_CLASS_ID, Class_ID (BOXOBJ_CLASS_ID, 0) );
|
|
|
|
IParamArray *iBoxParams = obj->GetParamBlock();
|
|
assert(iBoxParams);
|
|
|
|
// Set the value of width, height and length.
|
|
|
|
int width_index = obj->GetParamBlockIndex(BOXOBJ_WIDTH);
|
|
assert(width_index >= 0);
|
|
iBoxParams->SetValue(width_index,TimeValue(0),Length / 4);
|
|
|
|
int height_index = obj->GetParamBlockIndex(BOXOBJ_HEIGHT);
|
|
assert(height_index >= 0);
|
|
iBoxParams->SetValue(height_index,TimeValue(0),Length);
|
|
|
|
int length_index = obj->GetParamBlockIndex(BOXOBJ_LENGTH);
|
|
assert(length_index >= 0);
|
|
iBoxParams->SetValue(length_index,TimeValue(0),Length / 4);
|
|
|
|
Node->Reference ( (Object *) obj );
|
|
|
|
Node->GetINode ()->SetNodeTM ( 0, Axis_tm );
|
|
|
|
// Add the node to the scene.
|
|
|
|
import_interface->AddNodeToScene ( Node );
|
|
|
|
// Add an AppData chunk to the inode to indicate which transformation
|
|
// axes are active.
|
|
|
|
ASF_Data_Chunk * data_p = (ASF_Data_Chunk *)
|
|
malloc ( sizeof (ASF_Data_Chunk) );
|
|
|
|
*data_p = Active_axes;
|
|
|
|
add_app_data ( 1, data_p, sizeof (ASF_Data_Chunk) );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Bone_Class::set_parent
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Bone_Class::set_parent ( Bone_Class * parent_bone )
|
|
{
|
|
Parent_bone = parent_bone;
|
|
parent_bone->Node->GetINode ()->AttachChild ( Node->GetINode () );
|
|
|
|
// Build the child node's transform matrix.
|
|
|
|
Matrix3 parent_tm = Node->GetINode ()->GetParentTM ( 0 );
|
|
|
|
Matrix3 child_tm = Axis_tm;
|
|
child_tm.Translate ( Normalize (parent_bone->Direction) *
|
|
parent_bone->Length );
|
|
child_tm.Translate ( parent_tm.GetTrans () );
|
|
|
|
Node->GetINode ()->SetNodeTM ( 0, child_tm );
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Bone_Class::add_app_data
|
|
//----------------------------------------------------------------------------
|
|
|
|
void Bone_Class::add_app_data ( int chunk_id, void * data, int data_size )
|
|
{
|
|
Node->GetINode ()->AddAppDataChunk
|
|
(
|
|
Class_ID(0x74975aa6, 0x1810323f),
|
|
SCENE_IMPORT_CLASS_ID,
|
|
chunk_id,
|
|
data_size,
|
|
data
|
|
);
|
|
}
|
|
|