Files
FC1/Editor/Ase/ASEParser.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

509 lines
10 KiB
C++

#include "StdAfx.h"
#include "AseParser.h"
#include "ASETokens.h"
#include <IMovieSystem.h>
//////////////////////////////////////////////////////////////////////////
CASEParser::CASEParser()
{
m_currentPos = 0;
m_animObject = 0;
m_node = 0;
}
//////////////////////////////////////////////////////////////////////////
float CASEParser::TickToTime( int ticks )
{
return (float)ticks / (m_scene.ticksPerFrame*m_scene.frameSpeed);
}
//////////////////////////////////////////////////////////////////////////
bool CASEParser::Compare( const char* token, const char* id )
{
if (!token)
return FALSE;
return stricmp(token, id) == 0;
}
//////////////////////////////////////////////////////////////////////////
char* CASEParser::GetToken()
{
static char str[512];
char* p;
int ch;
BOOL quoted = FALSE;
p = str;
// Skip white space
while (isspace(ch = GetChar()) && !IsEof());
// Are we at end of file?
if (IsEof())
{
return NULL;
}
if (ch == '\"')
{
quoted = TRUE;
}
// Read everything that is not white space into the token buffer
do
{
*p = ch;
p++;
ch = GetChar();
if (ch == '\"')
{
quoted = FALSE;
}
} while ((quoted || !isspace(ch)) && !IsEof());
*p = '\0';
if (str[0] == '\0')
return NULL;
return str;
}
// Skip to the end of this block.
bool CASEParser::SkipBlock()
{
char* token;
int level = 1;
do
{
token = GetToken();
if (Compare(token, "{"))
level++;
else if (Compare(token, "}"))
level--;
} while (level > 0);
return true;
}
//////////////////////////////////////////////////////////////////////////
Vec3d CASEParser::GetVec3()
{
char* token;
Vec3d p;
token = GetToken();
p.x = (float)atof(token);
token = GetToken();
p.y = (float)atof(token);
token = GetToken();
p.z = (float)atof(token);
return p;
}
//////////////////////////////////////////////////////////////////////////
Quat CASEParser::GetQuat()
{
char* token;
Quat q;
token = GetToken();
q.x = (float)atof(token);
token = GetToken();
q.y = (float)atof(token);
token = GetToken();
q.z = (float)atof(token);
token = GetToken();
q.w = (float)atof(token);
return q;
}
//////////////////////////////////////////////////////////////////////////
float CASEParser::GetFloat()
{
char* token;
float f;
token = GetToken();
f = (float)atof(token);
return f;
}
//////////////////////////////////////////////////////////////////////////
int CASEParser::GetInt()
{
char* token;
int i;
token = GetToken();
i = atoi(token);
return i;
}
//////////////////////////////////////////////////////////////////////////
const char* CASEParser::GetString()
{
static std::string str;
str = GetToken();
str = str.substr( 1,str.length()-2 );
return str.c_str();
}
//////////////////////////////////////////////////////////////////////////
CAnimObject::Node* CASEParser::FindNode( const char *sNodeName )
{
NodeMap::iterator it = m_nodeMap.find(sNodeName);
if (it == m_nodeMap.end())
return 0;
return it->second;
}
//////////////////////////////////////////////////////////////////////////
Vec3 CASEParser::ScalePosition( const Vec3 &pos )
{
return pos * (1.0f/100.0f);
}
//////////////////////////////////////////////////////////////////////////
void CASEParser::ParseGeomNode()
{
Vec3 nodePos(0,0,0);
Vec3 nodeScale(1,1,1);
Vec3 nodeRotAxis(0,0,0);
float nodeRotAngle = 0;
// New node.
m_node = 0;
int level = 0;
const char *str;
char *token;
do
{
token = GetToken();
if (Compare(token, "{"))
level++;
else if (Compare(token, "}"))
level--;
else if (Compare(token,ASE_NODE_NAME))
{
if (level == 1)
{
str = GetString();
m_node = m_animObject->CreateNode(str);
m_nodeMap[str] = m_node;
}
continue;
}
if (!m_node)
continue;
if (Compare(token,ASE_NODE_PARENT))
{
str = GetString();
m_node->m_parent = FindNode(str);
}
else if (Compare(token,ASE_TM_POS))
{
nodePos = ScalePosition(GetVec3());
}
else if (Compare(token,ASE_TM_SCALE))
{
nodeScale = GetVec3();
}
else if (Compare(token,ASE_TM_ROTANGLE))
{
nodeRotAngle = GetFloat();
}
else if (Compare(token,ASE_TM_ROTAXIS))
{
nodeRotAxis = GetVec3();
}
else if (Compare(token,ASE_TM_ANIMATION))
{
ParseTMAnimation();
}
} while (level > 0);
if (m_node)
{
Quat q;
q.SetFromAngleAxis( nodeRotAngle,nodeRotAxis );
m_node->m_pos = nodePos;
m_node->m_scale = nodeScale;
m_node->m_rotate = q;
Matrix tm;
q.GetMatrix(tm);
tm.ScaleMatrix( nodeScale.x,nodeScale.y,nodeScale.z );
tm.SetTranslation( nodePos );
tm.Invert();
if (m_node->m_parent)
m_node->m_invOrigTM = tm * m_node->m_parent->m_invOrigTM;
else
m_node->m_invOrigTM = tm;
}
}
//////////////////////////////////////////////////////////////////////////
void CASEParser::ParseTMAnimation()
{
std::vector<ITcbKey> posTableTcb;
std::vector<ITcbKey> rotTableTcb;
std::vector<ITcbKey> scaleTableTcb;
// Optimize allocations.
posTableTcb.reserve( 10 );
rotTableTcb.reserve( 10 );
scaleTableTcb.reserve( 10 );
// Parse node animation.
Quat prevQ;
prevQ.Identity();
int level = 0;
char *token;
do
{
token = GetToken();
if (Compare(token, "{"))
level++;
else if (Compare(token, "}"))
level--;
else if (Compare(token,ASE_CONTROL_POS_TCB))
{
// Tcb Position controller.
m_node->m_posTrack = GetIEditor()->GetMovieSystem()->CreateTrack( ATRACK_TCB_VECTOR );
m_node->m_posTrack->SetFlags( ATRACK_CYCLE );
}
else if (Compare(token,ASE_CONTROL_ROT_TCB))
{
// Tcb Position controller.
m_node->m_rotTrack = GetIEditor()->GetMovieSystem()->CreateTrack( ATRACK_TCB_QUAT );
m_node->m_rotTrack->SetFlags( ATRACK_CYCLE );
}
else if (Compare(token,ASE_CONTROL_SCALE_TCB))
{
// Tcb Position controller.
m_node->m_scaleTrack = GetIEditor()->GetMovieSystem()->CreateTrack( ATRACK_TCB_VECTOR );
m_node->m_scaleTrack->SetFlags( ATRACK_CYCLE );
}
/*********************************************************************/
//
// Controller keys
//
/*********************************************************************/
else if (Compare(token, ASE_POS_SAMPLE) || Compare(token, ASE_POS_KEY))
{
/*
PosKeeper* p = new PosKeeper;
p->t = GetInt();
p->val = GetVec3();
// Bezier tangents
p->inTan = p->val;
p->outTan = p->val;
p->flags = 0;
p->type = kBez;
posTable.Append(1, &p, 5);
*/
}
else if (Compare(token, ASE_BEZIER_POS_KEY))
{
/*
PosKeeper* p = new PosKeeper;
p->t = GetInt();
p->val = GetVec3();
// Bezier tangents
p->inTan = GetVec3();
p->outTan = GetVec3();
p->flags = GetInt();
p->type = kBez;
posTable.Append(1, &p, 5);
*/
}
else if (Compare(token, ASE_TCB_POS_KEY))
{
ITcbKey key;
key.time = TickToTime(GetInt());
key.SetVec3( ScalePosition(GetVec3()) );
key.tens = GetFloat();
key.cont = GetFloat();
key.bias = GetFloat();
key.easeto = GetFloat();
key.easefrom = GetFloat();
posTableTcb.push_back(key);
}
else if (Compare(token, ASE_TCB_ROT_KEY))
{
ITcbKey key;
key.time = TickToTime(GetInt());
Vec3 axis = GetVec3();
float angle = GetFloat();
key.tens = GetFloat();
key.cont = GetFloat();
key.bias = GetFloat();
key.easeto = GetFloat();
key.easefrom = GetFloat();
Quat q;
q.SetFromAngleAxis( angle,axis );
// Rotation in ASE file is relative, so we must convert it to absolute.
q = q * prevQ;
prevQ = q;
key.SetQuat(q);
rotTableTcb.push_back(key);
}
else if (Compare(token, ASE_TCB_SCALE_KEY))
{
ITcbKey key;
key.time = TickToTime(GetInt());
key.SetVec3( GetVec3() );
key.tens = GetFloat();
key.cont = GetFloat();
key.bias = GetFloat();
key.easeto = GetFloat();
key.easefrom = GetFloat();
scaleTableTcb.push_back(key);
}
} while (level > 0);
if (m_node->m_posTrack)
{
m_node->m_posTrack->SetNumKeys(posTableTcb.size());
for (int i = 0; i < posTableTcb.size(); i++)
{
m_node->m_posTrack->SetKey( i,&posTableTcb[i] );
}
}
if (m_node->m_rotTrack)
{
m_node->m_rotTrack->SetNumKeys(rotTableTcb.size());
for (int i = 0; i < rotTableTcb.size(); i++)
{
m_node->m_rotTrack->SetKey( i,&rotTableTcb[i] );
}
/*
FILE *file = fopen( "Objects\\sampl.txt","wt" );
prevQ.Identity();
// Sample rot track.
for (int t = 0; t < 14400; t+= 160)
{
Quat qval;
m_node->m_rotTrack->GetValue( t,qval );
Quat q = qval / prevQ;
prevQ = qval;
q = q.GetAngleAxis();
fprintf( file,"%d: %.4f,%.4f,%.4f,%.4f\n",t,q.x,q.y,q.z,q.w );
}
fclose(file);
*/
}
if (m_node->m_scaleTrack)
{
m_node->m_scaleTrack->SetNumKeys(scaleTableTcb.size());
for (int i = 0; i < scaleTableTcb.size(); i++)
{
m_node->m_scaleTrack->SetKey( i,&scaleTableTcb[i] );
}
}
}
//////////////////////////////////////////////////////////////////////////
// Get scene parameters from the file
void CASEParser::ParseSceneParams()
{
char* token;
int level = 0;
do
{
token = GetToken();
if (Compare(token, ASE_FIRSTFRAME))
{
m_scene.firstFrame = GetInt();
}
else if (Compare(token, ASE_LASTFRAME))
{
m_scene.lastFrame = GetInt();
}
else if (Compare(token, ASE_FRAMESPEED))
{
m_scene.frameSpeed = GetInt();
}
else if (Compare(token, ASE_TICKSPERFRAME))
{
m_scene.ticksPerFrame = GetInt();
}
else if (Compare(token, "{"))
level++;
else if (Compare(token, "}"))
level--;
} while (level > 0);
}
//////////////////////////////////////////////////////////////////////////
bool CASEParser::ParseString( CAnimObject *object,const char *buffer )
{
m_animObject = object;
m_buffer = buffer;
char *token;
while (token = GetToken())
{
if (Compare(token,ASE_SCENE))
{
ParseSceneParams();
}
else if (Compare(token,ASE_GEOMETRY))
{
ParseGeomNode();
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CASEParser::Parse( CAnimObject *object,const char *filename )
{
m_animObject = object;
FILE *file = fopen(filename,"rb");
if (file)
{
fseek( file,0,SEEK_END );
int fsize = ftell(file);
fseek( file,0,SEEK_SET );
char *buf = new char[fsize+1];
fread( buf,fsize,1,file );
buf[fsize] = 0;
ParseString( m_animObject,buf );
delete []buf;
fclose(file);
}
return true;
}