Initial commit of Command & Conquer Renegade source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:39:46 +00:00
parent 74ab8fa5e0
commit 58ed459113
4918 changed files with 1366710 additions and 0 deletions

View File

@@ -0,0 +1,135 @@
# Microsoft Developer Studio Project File - Name="asf_imp" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=asf_imp - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "ASF_IMP.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "ASF_IMP.mak" CFG="asf_imp - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "asf_imp - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "asf_imp - Win32 Hybrid" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Commando/Code/Tools/ASF_IMP", SGHAAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "asf_imp - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir ".\Release"
# PROP BASE Intermediate_Dir ".\Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
# ADD CPP /nologo /MD /W3 /GX /Z7 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib core.lib geom.lib maxutil.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Release/asf_imp.dli"
# SUBTRACT LINK32 /nodefaultlib
!ELSEIF "$(CFG)" == "asf_imp - Win32 Hybrid"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Hybrid"
# PROP BASE Intermediate_Dir "Hybrid"
# PROP BASE Ignore_Export_Lib 0
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Hybrid"
# PROP Intermediate_Dir "Hybrid"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /Z7 /O2 /I "c:\3dsmax2\maxsdk\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /Z7 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib core.lib geom.lib util.lib /nologo /subsystem:windows /dll /machine:I386 /out:"Hybrid/asf_imp.dli"
# SUBTRACT BASE LINK32 /nodefaultlib
# ADD LINK32 odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib core.lib geom.lib maxutil.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"Hybrid\asf_imp.dli"
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
# Begin Target
# Name "asf_imp - Win32 Release"
# Name "asf_imp - Win32 Hybrid"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
# Begin Source File
SOURCE=.\ASF_import.cpp
# End Source File
# Begin Source File
SOURCE=.\ASF_import.def
# End Source File
# Begin Source File
SOURCE=.\Read_ASF.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
# Begin Source File
SOURCE=.\asf_data.h
# End Source File
# Begin Source File
SOURCE=.\exception.h
# End Source File
# Begin Source File
SOURCE=.\read_asf.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\ASF_import.rc
# End Source File
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,280 @@
/*
** 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/>.
*/
//----------------------------------------------------------------------------
// asf_import.cpp
//
// Acclaim Skeleton File import module
//
// James McNeill
//
// Created October 1996
//
// Copyright (c) 1996 Westwood Studios
//----------------------------------------------------------------------------
#include <Max.h>
#include <istdplug.h>
#include <splshape.h>
#include <dummy.h>
#include "asf_resource.h"
#include "asf_data.h"
#include "read_asf.h"
#include "exception.h"
static HINSTANCE hInstance;
static TCHAR * GetString ( int id )
{
static TCHAR buf[256];
if (hInstance)
return LoadString(hInstance, id, buf, sizeof(buf)) ? buf : NULL;
return NULL;
}
static int MessageBox ( int s1, int s2, int option = MB_OK )
{
TSTR str1(GetString(s1));
TSTR str2(GetString(s2));
return MessageBox(GetActiveWindow(), str1, str2, option);
}
static int Alert ( int s1, int s2 = IDS_LIB_SHORT_DESC, int option = MB_OK )
{
return MessageBox(s1, s2, option);
}
//----------------------------------------------------------------------------
// ASF_Import
//----------------------------------------------------------------------------
class ASF_Import : public SceneImport
{
public:
ASF_Import();
~ASF_Import();
int ExtCount(); // Number of extensions supported
const TCHAR * Ext(int n); // Extension #n
const TCHAR * LongDesc(); // Long ASCII description
const TCHAR * ShortDesc(); // Short ASCII description
const TCHAR * AuthorName(); // ASCII Author name
const TCHAR * CopyrightMessage(); // ASCII Copyright message
const TCHAR * OtherMessage1(); // Other message #1
const TCHAR * OtherMessage2(); // Other message #2
unsigned int Version(); // Version number * 100
void ShowAbout(HWND); // Show DLL's "About..." box
int DoImport
(
const TCHAR * name,
ImpInterface * i,
Interface * gi,
BOOL suppressPrompts=FALSE
);
};
//----------------------------------------------------------------------------
// DllMain
//----------------------------------------------------------------------------
static int controlsInit = FALSE;
BOOL WINAPI DllMain
(
HINSTANCE hinstDLL,
ULONG fdwReason,
LPVOID lpvReserved
)
{
hInstance = hinstDLL;
if ( !controlsInit )
{
controlsInit = TRUE;
InitCustomControls(hInstance);
InitCommonControls();
}
switch(fdwReason)
{
case DLL_PROCESS_ATTACH: break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: break;
}
return TRUE;
}
//----------------------------------------------------------------------------
// ASF_ClassDesc
//----------------------------------------------------------------------------
class ASF_ClassDesc : public ClassDesc
{
public:
int IsPublic() { return 1; }
void * Create(BOOL loading = FALSE) { return new ASF_Import; }
const TCHAR * ClassName() { return GetString(IDS_SHORT_DESC); }
SClass_ID SuperClassID() { return SCENE_IMPORT_CLASS_ID; }
Class_ID ClassID() { return Class_ID(0x74975aa6, 0x1810323f); }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
};
static ASF_ClassDesc ASF_desc;
//----------------------------------------------------------------------------
// This is the interface to Jaguar:
//----------------------------------------------------------------------------
__declspec( dllexport ) const TCHAR * LibDescription()
{
return GetString(IDS_LIB_LONG_DESC);
}
__declspec( dllexport ) int LibNumberClasses()
{
return 1;
}
__declspec( dllexport ) ClassDesc * LibClassDesc(int i)
{
switch(i)
{
case 0: return & ASF_desc; break;
default: return 0; break;
}
}
// Return version so can detect obsolete DLLs
__declspec( dllexport ) ULONG LibVersion()
{
return VERSION_3DSMAX;
}
//
// ASF import module functions follow:
//
ASF_Import::ASF_Import() {}
ASF_Import::~ASF_Import() {}
int ASF_Import::ExtCount()
{
return 1;
}
// Extensions supported for import/export modules
const TCHAR * ASF_Import::Ext(int n)
{
if ( n == 0 ) return _T("ASF");
else return _T("");
}
const TCHAR * ASF_Import::LongDesc()
{
return GetString(IDS_LONG_DESC);
}
const TCHAR * ASF_Import::ShortDesc()
{
return GetString(IDS_SHORT_DESC);
}
const TCHAR * ASF_Import::AuthorName()
{
return GetString(IDS_AUTHOR_NAME);
}
const TCHAR * ASF_Import::CopyrightMessage()
{
return GetString(IDS_COPYRIGHT);
}
const TCHAR * ASF_Import::OtherMessage1()
{
return _T("");
}
const TCHAR * ASF_Import::OtherMessage2()
{
return _T("");
}
unsigned int ASF_Import::Version()
{
return 100;
}
void ASF_Import::ShowAbout(HWND hWnd)
{
}
//----------------------------------------------------------------------------
// asf_load
//----------------------------------------------------------------------------
static int asf_load
(
const TCHAR * filename,
ImpInterface * iface,
Interface * gi
)
{
// Load the skeleton definition file.
try
{
Skeleton_Class skeleton ( filename, iface, gi );
}
catch ( const Parse_Error & error )
{
MessageBox ( GetActiveWindow (), error.message (), "Parse error",
MB_OK );
return -1;
}
// Create a matching skeleton in 3DS Max.
return 1;
}
//----------------------------------------------------------------------------
// ASF_Import::DoImport
//----------------------------------------------------------------------------
int ASF_Import::DoImport
(
const TCHAR * filename,
ImpInterface * iface,
Interface * gi,
BOOL
)
{
int status;
status = asf_load ( filename, iface, gi );
if(status == 0)
status = IMPEXP_CANCEL;
return (status <= 0) ? IMPEXP_FAIL : status;
}

View File

@@ -0,0 +1,8 @@
LIBRARY asf_imp
EXPORTS
LibDescription @1
LibNumberClasses @2
LibClassDesc @3
LibVersion @4
SECTIONS
.data READ WRITE

View File

@@ -0,0 +1,147 @@
//Microsoft Developer Studio generated resource script.
//
#include "asf_resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_IMPORTOPTIONS DIALOG DISCARDABLE 0, 0, 123, 266
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Import DXF File"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,67,231,50,14
PUSHBUTTON "Cancel",IDCANCEL,67,247,50,14
GROUPBOX "Derive Objects From:",IDC_STATIC,6,4,112,50
CONTROL "&Layer",IDC_OBJ_LAYER,"Button",BS_AUTORADIOBUTTON |
WS_TABSTOP,44,17,29,10
CONTROL "&Color",IDC_OBJ_COLOR,"Button",BS_AUTORADIOBUTTON,44,28,
28,10
CONTROL "&Entity",IDC_OBJ_ENTITY,"Button",BS_AUTORADIOBUTTON,44,
38,30,10
GROUPBOX "Weld Vertices:",IDC_STATIC,6,57,112,41
RTEXT "Weld Threshold:",IDC_STATIC,13,72,55,8
CONTROL "",IDC_WELDENTRY,"CustEdit",WS_TABSTOP,69,71,36,10
CONTROL "",IDC_WELDSPINNER,"SpinnerControl",0x0,106,71,7,10
CONTROL "&Weld",IDC_WELD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
47,83,30,10
GROUPBOX "Auto-Smooth:",IDC_STATIC,6,102,112,40
RTEXT "Smooth Angle:",IDC_STATIC,16,117,48,8
CONTROL "",IDC_SMOOTHENTRY,"CustEdit",WS_TABSTOP,65,117,36,10
CONTROL "",IDC_SMOOTHSPINNER,"SpinnerControl",0x0,102,117,7,10
CONTROL "&Auto-Smooth",IDC_AUTOSMOOTH,"Button",BS_AUTOCHECKBOX |
WS_TABSTOP,34,128,53,10
GROUPBOX "Arc Degrees:",IDC_STATIC,6,146,112,30
RTEXT "&Degrees:",IDC_STATIC,23,161,31,8
CONTROL "00",IDC_ARCENTRY,"CustEdit",WS_TABSTOP,56,160,36,10
CONTROL "",IDC_ARCSPINNER,"SpinnerControl",0x0,93,160,7,10
GROUPBOX "Miscellaneous:",IDC_STATIC,6,180,112,46
CONTROL "&Remove Double Faces",IDC_REMOVEDOUBLES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,19,193,85,10
CONTROL "&Fill Polylines",IDC_FILLPOLYLINES,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,19,203,52,10
CONTROL "&Unify Normals",IDC_UNIFYNORMALS,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,19,213,56,10
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"asf_resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_LIB_SHORT_DESC "ASF Import"
IDS_LIB_LONG_DESC "Acclaim Skeleton Format Import DLL"
IDS_IMPORTING_ASF "Importing ASF"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_ERR_OPENING_FILE "Error opening file"
IDS_TH_OUTOFMEMORY "Out of memory"
IDS_SHORT_DESC "ASF File"
IDS_LONG_DESC "Acclaim Skeleton Format File"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_CATEGORY "Scene Import"
IDS_AUTHOR_NAME "James McNeill"
IDS_COPYRIGHT "Copyright 1996 Westwood Studios"
END
STRINGTABLE DISCARDABLE
BEGIN
IDS_BAD_HEADER "Bad header in CME file."
IDS_UNEXPECTED_EOF "Unexpected end of file in CME file."
IDS_NODE_CREATION_ERROR "Node creation error."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,62 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by ASF_import.rc
//
#define IDD_IMPORTOPTIONS 101
#define IDC_OBJ_LAYER 1000
#define IDC_OBJ_COLOR 1001
#define IDC_OBJ_ENTITY 1002
#define IDC_REMOVEDOUBLES 1004
#define IDC_FILLPOLYLINES 1005
#define IDC_AUTOSMOOTH 1006
#define IDC_WELDENTRY 1007
#define IDC_WELDSPINNER 1008
#define IDC_SMOOTHSPINNER 1009
#define IDC_SMOOTHENTRY 1010
#define IDC_ARCSPINNER 1011
#define IDC_ARCENTRY 1012
#define IDC_WELD 1013
#define IDC_UNIFYNORMALS 1014
#define IDC_DBG1 1015
#define IDS_TH_SCENEIMPORT 40217
#define IDS_CATEGORY 40217
#define IDS_TH_TOM_HUDSON 40222
#define IDS_AUTHOR_NAME 40222
#define IDS_TH_COPYRIGHT_YOST_GROUP 40223
#define IDS_COPYRIGHT 40223
#define IDS_TH_ERR_OPENING_FILE 40225
#define IDS_ERR_OPENING_FILE 40225
#define IDS_TH_OUTOFMEMORY 40230
#define IDS_TH_AUTOCAD 40236
#define IDS_SHORT_DESC 40236
#define IDS_TH_AUTOCADDXFFILE 40238
#define IDS_LONG_DESC 40238
#define IDS_TH_DXFIMP 40240
#define IDS_LIB_SHORT_DESC 40240
#define IDS_TH_DXFIMPORTDLL 40241
#define IDS_LIB_LONG_DESC 40241
#define IDS_TH_PARTIALREAD 40242
#define IDS_TH_UNKNOWNERR 40243
#define IDS_TH_FINALIZING 40244
#define IDS_TH_IMPORTINGDXF 40245
#define IDS_IMPORTING_CME 40245
#define IDS_IMPORTING_ASF 40245
#define IDS_TH_INVALIDRATSNEST 40253
#define IDS_TH_INVALIDSPLINEMESH 40254
#define IDS_TH_INVALID3DMESH 40255
#define IDS_TH_ERRORINDXF 40256
#define IDS_BAD_HEADER 40257
#define IDS_UNEXPECTED_EOF 40258
#define IDS_NODE_CREATION_ERROR 40259
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1016
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,818 @@
/*
** 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
);
}

View File

@@ -0,0 +1,61 @@
/*
** 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/>.
*/
//----------------------------------------------------------------------------
// Axes
//----------------------------------------------------------------------------
enum Axis_Names
{
ROTATE_X,
ROTATE_Y,
ROTATE_Z,
TRANSLATE_X,
TRANSLATE_Y,
TRANSLATE_Z,
TRANSLATE_LENGTH
};
//----------------------------------------------------------------------------
// ASF_Data_Chunk
//----------------------------------------------------------------------------
struct ASF_Data_Chunk
{
ASF_Data_Chunk () : Number_of_axes (0) {}
void add_axis ( Axis_Names new_axis )
{
if ( Number_of_axes < 7 )
{
Axis [Number_of_axes] = new_axis;
++ Number_of_axes;
}
}
unsigned Number_of_axes;
Axis_Names Axis [ 7 ];
};
//----------------------------------------------------------------------------
// Position_Key_Scale_Chunk
//----------------------------------------------------------------------------
struct Position_Key_Scale_Chunk
{
float Position_Key_Scale;
};

View File

@@ -0,0 +1,45 @@
/*
** 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/>.
*/
class Exception
{
public:
virtual const char * message () const
{
return "General exception.";
}
};
class Parse_Error : public Exception
{
public:
Parse_Error ( const char * message ) :
Message (message)
{}
virtual const char * message () const
{
return Message;
}
protected:
const char * Message;
};

View File

@@ -0,0 +1,194 @@
/*
** 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/>.
*/
//----------------------------------------------------------------------------
// File_Class
//----------------------------------------------------------------------------
class File_Class
{
public:
FILE * fp;
File_Class ( const char * filename, const char * mode )
{
fp = fopen ( filename, mode );
}
~File_Class ()
{
if ( fp != NULL )
fclose ( fp );
fp = NULL;
}
};
//----------------------------------------------------------------------------
// ASF_Lexeme_Type
//----------------------------------------------------------------------------
enum ASF_Lexeme_Type
{
EOF_MARKER,
TOKEN,
NEWLINE
};
//----------------------------------------------------------------------------
// ASF_Lexer
//----------------------------------------------------------------------------
#define MAX_TOKEN_LENGTH 512
class ASF_Lexer
{
public:
ASF_Lexer ( const char * file_name );
ASF_Lexeme_Type type () const { return Current_type; }
const char * text () const { return Current_text; }
void advance ();
protected:
void skip_whitespace ();
File_Class Input_file;
int Current_char;
ASF_Lexeme_Type Current_type;
char Current_text [ MAX_TOKEN_LENGTH ];
};
//----------------------------------------------------------------------------
// Bone_Class
//----------------------------------------------------------------------------
class Bone_Class
{
public:
Bone_Class ():
Name (""),
Direction (Point3 (0,0,0)),
Parent_bone (NULL),
Next_bone (NULL),
Length (0.0f)
{
Axis_tm.IdentityMatrix ();
}
~Bone_Class () { delete [] Name; }
void set_name ( const char * name )
{
Name = new char [ strlen (name) + 1 ];
strcpy ( Name, name );
}
void set_next_bone ( Bone_Class * next_bone )
{
Next_bone = next_bone;
}
void set_length ( float length ) { Length = length; }
void set_direction ( Point3 direction ) { Direction = direction; }
void set_axis_tm ( const Matrix3 & axis_tm ) { Axis_tm = axis_tm; }
void add_axis ( Axis_Names axis ) { Active_axes.add_axis ( axis ); }
void set_parent ( Bone_Class * parent_bone );
const char * name () const { return Name; }
Bone_Class * next_bone () const { return Next_bone; }
void create_node
(
ImpInterface * import_interface,
Interface * max_interface
);
void add_app_data ( int chunk_id, void * data, int data_size );
private:
char * Name;
Point3 Direction;
Matrix3 Axis_tm;
Bone_Class * Parent_bone;
Bone_Class * Next_bone;
ImpNode * Node;
float Length;
ASF_Data_Chunk Active_axes;
};
//----------------------------------------------------------------------------
// Skeleton_Class
//----------------------------------------------------------------------------
#define DEGREES_TO_RADIANS 1.7453293e-2f
class Skeleton_Class
{
public:
Skeleton_Class
(
const char * file_name,
ImpInterface *,
Interface *
);
~Skeleton_Class ();
protected:
void add_bone_to_list ( Bone_Class * new_bone );
Bone_Class * find_bone ( const char * name );
void parse_units_block ( ASF_Lexer & );
void parse_root_block ( ASF_Lexer & );
void parse_bonedata_block ( ASF_Lexer & );
void parse_hierarchy_block ( ASF_Lexer & );
void parse_hierarchy_line ( ASF_Lexer & );
void parse_bone ( ASF_Lexer & );
void skip_unrecognized_blocks ( ASF_Lexer & );
void skip_to_next_line ( ASF_Lexer & );
void match_newline ( ASF_Lexer & );
void match_token ( ASF_Lexer &, const char * );
void skip_token ( ASF_Lexer & );
void verify_token ( ASF_Lexer & );
float float_token ( ASF_Lexer & );
float Angle_multiplier; // Converts angle to radians.
float Length_multiplier;
ImpInterface * Import_interface;
Interface * Max_interface;
Bone_Class * First_bone;
};