2003-04-25 21:05:40 +00:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "Model.h"
|
2003-05-11 07:23:47 +00:00
|
|
|
#include "ModelTypes.h"
|
2003-12-20 03:54:21 +00:00
|
|
|
#include "RageMath.h"
|
2003-04-25 21:05:40 +00:00
|
|
|
#include "RageDisplay.h"
|
2003-04-27 05:14:27 +00:00
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "RageTextureManager.h"
|
2005-07-05 23:55:42 +00:00
|
|
|
#include "XmlFile.h"
|
2003-07-22 07:47:27 +00:00
|
|
|
#include "RageFile.h"
|
2003-08-20 09:15:53 +00:00
|
|
|
#include "RageLog.h"
|
2003-11-02 23:29:21 +00:00
|
|
|
#include "ActorUtil.h"
|
2004-02-08 09:04:23 +00:00
|
|
|
#include "ModelManager.h"
|
2004-08-09 00:46:42 +00:00
|
|
|
#include "Foreach.h"
|
2005-01-26 11:21:43 +00:00
|
|
|
#include "LuaBinding.h"
|
|
|
|
|
|
2005-04-01 23:46:45 +00:00
|
|
|
REGISTER_ACTOR_CLASS( Model )
|
|
|
|
|
|
2003-05-04 05:21:16 +00:00
|
|
|
const float FRAMES_PER_SECOND = 30;
|
2003-06-07 18:09:20 +00:00
|
|
|
const CString DEFAULT_ANIMATION_NAME = "default";
|
2003-05-04 05:21:16 +00:00
|
|
|
|
2005-08-30 03:46:20 +00:00
|
|
|
Model::Model()
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-05-15 06:09:19 +00:00
|
|
|
m_bTextureWrapping = true;
|
2003-11-18 20:33:18 +00:00
|
|
|
SetUseZBuffer( true );
|
2004-03-01 10:19:07 +00:00
|
|
|
SetCullMode( CULL_BACK );
|
2004-02-08 09:04:23 +00:00
|
|
|
m_pGeometry = NULL;
|
2003-06-07 18:09:20 +00:00
|
|
|
m_pCurAnimation = NULL;
|
2003-08-20 09:15:53 +00:00
|
|
|
m_bRevertToDefaultAnimation = false;
|
2003-08-31 08:15:52 +00:00
|
|
|
m_fDefaultAnimationRate = 1;
|
|
|
|
|
m_fCurAnimationRate = 1;
|
2004-04-16 05:09:02 +00:00
|
|
|
m_pTempGeometry = NULL;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-30 03:46:20 +00:00
|
|
|
Model::~Model()
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2005-08-30 03:46:20 +00:00
|
|
|
Clear();
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-30 03:46:20 +00:00
|
|
|
void Model::Clear()
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-02-08 09:04:23 +00:00
|
|
|
if( m_pGeometry )
|
|
|
|
|
{
|
|
|
|
|
MODELMAN->UnloadModel( m_pGeometry );
|
|
|
|
|
m_pGeometry = NULL;
|
|
|
|
|
}
|
2004-02-08 04:58:43 +00:00
|
|
|
m_vpBones.clear();
|
2003-06-07 18:09:20 +00:00
|
|
|
m_Materials.clear();
|
|
|
|
|
m_mapNameToAnimation.clear();
|
|
|
|
|
m_pCurAnimation = NULL;
|
2004-04-08 08:35:38 +00:00
|
|
|
|
2004-04-16 05:09:02 +00:00
|
|
|
if( m_pTempGeometry )
|
|
|
|
|
DISPLAY->DeleteCompiledGeometry( m_pTempGeometry );
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-02-08 11:17:03 +00:00
|
|
|
void Model::Load( CString sFile )
|
|
|
|
|
{
|
|
|
|
|
if( sFile == "" ) return;
|
|
|
|
|
|
|
|
|
|
CString sExt = GetExtension(sFile);
|
|
|
|
|
sExt.MakeLower();
|
|
|
|
|
if( sExt=="txt" )
|
|
|
|
|
LoadMilkshapeAscii( sFile );
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-19 02:35:40 +00:00
|
|
|
#define THROW RageException::Throw( "Parse error in \"%s\" at line %d: '%s'", sPath.c_str(), iLineNum, sLine.c_str() )
|
2004-01-21 06:19:43 +00:00
|
|
|
|
2004-02-08 11:17:03 +00:00
|
|
|
void Model::LoadMilkshapeAscii( CString sPath )
|
|
|
|
|
{
|
|
|
|
|
LoadPieces( sPath, sPath, sPath );
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-19 00:16:02 +00:00
|
|
|
void Model::LoadPieces( CString sMeshesPath, CString sMaterialsPath, CString sBonesPath )
|
2004-02-08 11:17:03 +00:00
|
|
|
{
|
|
|
|
|
Clear();
|
|
|
|
|
|
2005-01-14 10:23:22 +00:00
|
|
|
// TRICKY: Load materials before geometry so we can figure out whether the materials require normals.
|
|
|
|
|
|
2004-02-08 11:17:03 +00:00
|
|
|
LoadMaterialsFromMilkshapeAscii( sMaterialsPath );
|
|
|
|
|
|
2005-01-14 10:23:22 +00:00
|
|
|
ASSERT( m_pGeometry == NULL );
|
|
|
|
|
m_pGeometry = MODELMAN->LoadMilkshapeAscii( sMeshesPath, this->MaterialsNeedNormals() );
|
|
|
|
|
|
2005-02-10 02:40:56 +00:00
|
|
|
/* Validate material indices. */
|
|
|
|
|
for( unsigned i = 0; i < m_pGeometry->m_Meshes.size(); ++i )
|
|
|
|
|
{
|
|
|
|
|
const msMesh *pMesh = &m_pGeometry->m_Meshes[i];
|
|
|
|
|
|
|
|
|
|
if( pMesh->nMaterialIndex >= (int) m_Materials.size() )
|
|
|
|
|
RageException::Throw( "Model \"%s\" mesh \"%s\" references material index %i, but there are only %i materials",
|
|
|
|
|
sMeshesPath.c_str(), pMesh->szName, pMesh->nMaterialIndex, m_Materials.size() );
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-19 08:15:35 +00:00
|
|
|
if( LoadMilkshapeAsciiBones( DEFAULT_ANIMATION_NAME, sBonesPath ) )
|
|
|
|
|
PlayAnimation( DEFAULT_ANIMATION_NAME );
|
|
|
|
|
|
2004-02-08 11:17:03 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Setup temp vertices (if necessary)
|
|
|
|
|
//
|
2004-08-19 00:16:50 +00:00
|
|
|
if( m_pGeometry->HasAnyPerVertexBones() )
|
2004-02-08 11:17:03 +00:00
|
|
|
{
|
2004-04-16 05:09:02 +00:00
|
|
|
m_vTempMeshes = m_pGeometry->m_Meshes;
|
|
|
|
|
m_pTempGeometry = DISPLAY->CreateCompiledGeometry();
|
2005-01-14 10:23:22 +00:00
|
|
|
m_pTempGeometry->Set( m_vTempMeshes, this->MaterialsNeedNormals() );
|
2004-02-08 11:17:03 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-01 23:46:45 +00:00
|
|
|
void Model::LoadFromNode( const CString& sDir, const XNode* pNode )
|
|
|
|
|
{
|
|
|
|
|
Actor::LoadFromNode( sDir, pNode );
|
|
|
|
|
|
|
|
|
|
CString s1, s2, s3;
|
|
|
|
|
pNode->GetAttrValue( "Meshes", s1 );
|
|
|
|
|
pNode->GetAttrValue( "Materials", s2 );
|
|
|
|
|
pNode->GetAttrValue( "Bones", s3 );
|
|
|
|
|
if( !s1.empty() || !s2.empty() || !s3.empty() )
|
|
|
|
|
{
|
2005-07-05 06:59:29 +00:00
|
|
|
LuaHelpers::RunAtExpressionS( s1 );
|
|
|
|
|
LuaHelpers::RunAtExpressionS( s2 );
|
|
|
|
|
LuaHelpers::RunAtExpressionS( s3 );
|
|
|
|
|
|
2005-04-01 23:46:45 +00:00
|
|
|
ASSERT( !s1.empty() && !s2.empty() && !s3.empty() );
|
2005-07-05 06:59:29 +00:00
|
|
|
|
|
|
|
|
if( s1.Left(1) != "/" )
|
|
|
|
|
s1 = sDir+s1;
|
|
|
|
|
if( s2.Left(1) != "/" )
|
|
|
|
|
s2 = sDir+s2;
|
|
|
|
|
if( s3.Left(1) != "/" )
|
|
|
|
|
s3 = sDir+s3;
|
|
|
|
|
|
|
|
|
|
LoadPieces( s1, s2, s3 );
|
2005-04-01 23:46:45 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-02-08 11:17:03 +00:00
|
|
|
void Model::LoadMaterialsFromMilkshapeAscii( CString sPath )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-09-01 11:21:12 +00:00
|
|
|
FixSlashesInPlace(sPath);
|
2003-10-29 20:23:38 +00:00
|
|
|
const CString sDir = Dirname( sPath );
|
2003-04-27 05:14:27 +00:00
|
|
|
|
2003-12-04 23:05:23 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open( sPath ) )
|
|
|
|
|
RageException::Throw( "Model::LoadMilkshapeAscii Could not open \"%s\": %s", sPath.c_str(), f.GetError().c_str() );
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-01-21 06:19:43 +00:00
|
|
|
CString sLine;
|
|
|
|
|
int iLineNum = 0;
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-01-21 06:19:43 +00:00
|
|
|
while( f.GetLine( sLine ) > 0 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-01-21 06:19:43 +00:00
|
|
|
iLineNum++;
|
|
|
|
|
|
2005-08-30 03:46:20 +00:00
|
|
|
if( !strncmp (sLine, "//", 2) )
|
2003-04-25 21:05:40 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
int nFrame;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "Frames: %d", &nFrame) == 1 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
// ignore
|
|
|
|
|
// m_pModel->nTotalFrames = nFrame;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "Frame: %d", &nFrame) == 1 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
// ignore
|
|
|
|
|
// m_pModel->nFrame = nFrame;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// materials
|
|
|
|
|
//
|
|
|
|
|
int nNumMaterials = 0;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "Materials: %d", &nNumMaterials) == 1 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
m_Materials.resize( nNumMaterials );
|
2003-05-04 05:21:16 +00:00
|
|
|
|
2003-10-21 05:14:21 +00:00
|
|
|
char szName[256];
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2005-08-30 03:46:20 +00:00
|
|
|
for( int i = 0; i < nNumMaterials; i++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
msMaterial& Material = m_Materials[i];
|
2003-04-25 21:05:40 +00:00
|
|
|
|
|
|
|
|
// name
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "\"%[^\"]\"", szName) != 1 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2004-08-18 06:04:53 +00:00
|
|
|
Material.sName = szName;
|
2003-04-25 21:05:40 +00:00
|
|
|
|
|
|
|
|
// ambient
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector4 Ambient;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "%f %f %f %f", &Ambient[0], &Ambient[1], &Ambient[2], &Ambient[3]) != 4 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-04-25 21:05:40 +00:00
|
|
|
memcpy( &Material.Ambient, &Ambient, sizeof(Material.Ambient) );
|
|
|
|
|
|
|
|
|
|
// diffuse
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector4 Diffuse;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "%f %f %f %f", &Diffuse[0], &Diffuse[1], &Diffuse[2], &Diffuse[3]) != 4 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-04-25 21:05:40 +00:00
|
|
|
memcpy( &Material.Diffuse, &Diffuse, sizeof(Material.Diffuse) );
|
|
|
|
|
|
|
|
|
|
// specular
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector4 Specular;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf(sLine, "%f %f %f %f", &Specular[0], &Specular[1], &Specular[2], &Specular[3]) != 4 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-04-25 21:05:40 +00:00
|
|
|
memcpy( &Material.Specular, &Specular, sizeof(Material.Specular) );
|
|
|
|
|
|
|
|
|
|
// emissive
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector4 Emissive;
|
2005-08-30 03:46:20 +00:00
|
|
|
if( sscanf (sLine, "%f %f %f %f", &Emissive[0], &Emissive[1], &Emissive[2], &Emissive[3]) != 4 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-04-25 21:05:40 +00:00
|
|
|
memcpy( &Material.Emissive, &Emissive, sizeof(Material.Emissive) );
|
|
|
|
|
|
|
|
|
|
// shininess
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2004-08-10 22:19:06 +00:00
|
|
|
char *p;
|
|
|
|
|
float fShininess = strtof( sLine, &p );
|
2005-08-30 03:46:20 +00:00
|
|
|
if( p == sLine )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-04-25 21:05:40 +00:00
|
|
|
Material.fShininess = fShininess;
|
|
|
|
|
|
|
|
|
|
// transparency
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2004-08-10 22:19:06 +00:00
|
|
|
float fTransparency = strtof( sLine, &p );
|
2005-08-30 03:46:20 +00:00
|
|
|
if( p == sLine )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2003-05-04 05:21:16 +00:00
|
|
|
Material.fTransparency = fTransparency;
|
2003-04-25 21:05:40 +00:00
|
|
|
|
|
|
|
|
// diffuse texture
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2005-08-30 03:46:20 +00:00
|
|
|
strcpy( szName, "" );
|
|
|
|
|
sscanf( sLine, "\"%[^\"]\"", szName );
|
2004-08-18 06:04:53 +00:00
|
|
|
CString sDiffuseTexture = szName;
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-08-18 06:04:53 +00:00
|
|
|
if( sDiffuseTexture != "" )
|
2003-08-23 19:10:05 +00:00
|
|
|
{
|
2004-08-18 06:04:53 +00:00
|
|
|
CString sTexturePath = sDir + sDiffuseTexture;
|
2003-09-16 01:12:20 +00:00
|
|
|
FixSlashesInPlace( sTexturePath );
|
|
|
|
|
CollapsePath( sTexturePath );
|
|
|
|
|
if( IsAFile(sTexturePath) )
|
2004-01-28 08:53:40 +00:00
|
|
|
Material.diffuse.Load( sTexturePath );
|
2003-09-16 01:12:20 +00:00
|
|
|
else
|
2004-01-20 03:31:53 +00:00
|
|
|
{
|
|
|
|
|
CString sError = ssprintf( "'%s' references a texture '%s' that does not exist", sPath.c_str(), sTexturePath.c_str() );
|
|
|
|
|
RageException::Throw( sError );
|
|
|
|
|
}
|
2003-08-23 19:10:05 +00:00
|
|
|
}
|
|
|
|
|
|
2003-04-25 21:05:40 +00:00
|
|
|
// alpha texture
|
2004-01-21 06:19:43 +00:00
|
|
|
if( f.GetLine( sLine ) <= 0 )
|
2004-08-19 02:35:40 +00:00
|
|
|
THROW;
|
2005-08-30 03:46:20 +00:00
|
|
|
strcpy( szName, "" );
|
|
|
|
|
sscanf( sLine, "\"%[^\"]\"", szName );
|
2004-08-18 06:04:53 +00:00
|
|
|
CString sAlphaTexture = szName;
|
2004-01-28 08:53:40 +00:00
|
|
|
|
2004-08-18 06:04:53 +00:00
|
|
|
if( sAlphaTexture != "" )
|
2004-01-28 08:53:40 +00:00
|
|
|
{
|
2004-08-18 06:04:53 +00:00
|
|
|
CString sTexturePath = sDir + sAlphaTexture;
|
2004-01-28 08:53:40 +00:00
|
|
|
FixSlashesInPlace( sTexturePath );
|
|
|
|
|
CollapsePath( sTexturePath );
|
|
|
|
|
if( IsAFile(sTexturePath) )
|
|
|
|
|
Material.alpha.Load( sTexturePath );
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
CString sError = ssprintf( "'%s' references a texture '%s' that does not exist", sPath.c_str(), sTexturePath.c_str() );
|
|
|
|
|
RageException::Throw( sError );
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-04 23:05:23 +00:00
|
|
|
f.Close();
|
2003-05-04 05:21:16 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-19 08:15:35 +00:00
|
|
|
bool Model::LoadMilkshapeAsciiBones( CString sAniName, CString sPath )
|
2003-05-04 05:21:16 +00:00
|
|
|
{
|
2004-08-19 08:29:16 +00:00
|
|
|
m_mapNameToAnimation[sAniName] = msAnimation();
|
|
|
|
|
msAnimation &Animation = m_mapNameToAnimation[sAniName];
|
2004-01-21 06:19:43 +00:00
|
|
|
|
2004-08-19 08:29:16 +00:00
|
|
|
if( Animation.LoadMilkshapeAsciiBones( sAniName, sPath ) )
|
|
|
|
|
{
|
|
|
|
|
m_mapNameToAnimation.erase( sAniName );
|
|
|
|
|
return false;
|
2003-05-04 05:21:16 +00:00
|
|
|
}
|
2004-08-19 08:15:35 +00:00
|
|
|
|
2004-08-19 08:29:16 +00:00
|
|
|
return true;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2005-08-25 00:57:53 +00:00
|
|
|
bool Model::EarlyAbortDraw() const
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-02-14 03:38:34 +00:00
|
|
|
return m_pGeometry == NULL || m_pGeometry->m_Meshes.empty();
|
|
|
|
|
}
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-06-18 11:02:40 +00:00
|
|
|
void Model::DrawCelShaded()
|
|
|
|
|
{
|
|
|
|
|
this->SetGlow(RageColor(0,0,0,1));
|
2004-06-22 05:31:11 +00:00
|
|
|
this->SetDiffuseAlpha(0);
|
2004-06-19 21:00:38 +00:00
|
|
|
DISPLAY->SetPolygonMode( POLYGON_LINE );
|
|
|
|
|
DISPLAY->SetLineWidth( 4 );
|
2004-09-20 02:43:04 +00:00
|
|
|
this->SetZWrite( false );
|
2004-06-18 11:02:40 +00:00
|
|
|
this->Draw();
|
2004-06-22 05:31:11 +00:00
|
|
|
this->SetDiffuseAlpha(1);
|
2004-06-18 11:02:40 +00:00
|
|
|
this->SetGlow(RageColor(1,1,1,0));
|
2004-06-19 21:00:38 +00:00
|
|
|
DISPLAY->SetPolygonMode( POLYGON_FILL );
|
2004-09-20 02:43:04 +00:00
|
|
|
this->SetZWrite( true );
|
2004-06-18 11:02:40 +00:00
|
|
|
this->Draw();
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-14 03:38:34 +00:00
|
|
|
void Model::DrawPrimitives()
|
|
|
|
|
{
|
2005-02-27 08:31:41 +00:00
|
|
|
Actor::SetGlobalRenderStates(); // set Actor-specified render states
|
|
|
|
|
|
2003-09-23 05:39:24 +00:00
|
|
|
/* Don't if we're fully transparent */
|
2003-12-24 21:07:50 +00:00
|
|
|
if( m_pTempState->diffuse[0].a < 0.001f && m_pTempState->glow.a < 0.001f )
|
2003-09-23 05:39:24 +00:00
|
|
|
return;
|
|
|
|
|
|
2003-05-15 06:09:19 +00:00
|
|
|
DISPLAY->Scale( 1, -1, 1 ); // flip Y so positive is up
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2003-12-24 21:07:50 +00:00
|
|
|
//////////////////////
|
|
|
|
|
// render the diffuse pass
|
|
|
|
|
//////////////////////
|
|
|
|
|
if( m_pTempState->diffuse[0].a > 0 )
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->SetTextureModeModulate();
|
|
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
for( unsigned i = 0; i < m_pGeometry->m_Meshes.size(); ++i )
|
2003-12-24 21:07:50 +00:00
|
|
|
{
|
2004-08-19 01:47:58 +00:00
|
|
|
const msMesh *pMesh = &m_pGeometry->m_Meshes[i];
|
2003-12-24 21:07:50 +00:00
|
|
|
|
2004-06-18 11:02:40 +00:00
|
|
|
|
2004-01-28 08:53:40 +00:00
|
|
|
if( pMesh->nMaterialIndex != -1 ) // has a material
|
2003-12-24 21:07:50 +00:00
|
|
|
{
|
2004-08-19 01:47:58 +00:00
|
|
|
// apply material
|
2003-12-24 21:07:50 +00:00
|
|
|
msMaterial& mat = m_Materials[ pMesh->nMaterialIndex ];
|
2004-06-18 11:02:40 +00:00
|
|
|
|
2003-12-24 21:07:50 +00:00
|
|
|
RageColor Emissive = mat.Emissive;
|
|
|
|
|
RageColor Ambient = mat.Ambient;
|
|
|
|
|
RageColor Diffuse = mat.Diffuse;
|
|
|
|
|
|
2004-01-12 02:57:26 +00:00
|
|
|
Emissive *= m_pTempState->diffuse[0];
|
|
|
|
|
Ambient *= m_pTempState->diffuse[0];
|
|
|
|
|
Diffuse *= m_pTempState->diffuse[0];
|
2003-12-24 21:07:50 +00:00
|
|
|
|
2004-06-18 11:02:40 +00:00
|
|
|
DISPLAY->SetMaterial( Emissive, Ambient, Diffuse, mat.Specular, mat.fShininess );
|
2004-01-28 08:53:40 +00:00
|
|
|
|
2005-05-01 00:02:08 +00:00
|
|
|
RageVector2 vTexTranslate = mat.diffuse.GetTextureTranslate();
|
|
|
|
|
if( vTexTranslate.x != 0 || vTexTranslate.y != 0 )
|
2005-05-01 00:06:53 +00:00
|
|
|
{
|
|
|
|
|
DISPLAY->TexturePushMatrix();
|
2005-10-04 19:45:45 +00:00
|
|
|
DISPLAY->TextureTranslate( vTexTranslate.x, vTexTranslate.y );
|
2005-05-01 00:06:53 +00:00
|
|
|
}
|
2004-01-28 08:53:40 +00:00
|
|
|
|
2005-01-04 05:38:44 +00:00
|
|
|
/* There's some common code that could be folded out here, but it seems
|
|
|
|
|
* clearer to keep it separate. */
|
|
|
|
|
if( DISPLAY->GetNumTextureUnits() < 2 )
|
|
|
|
|
{
|
|
|
|
|
// render the diffuse texture
|
|
|
|
|
DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() );
|
2005-02-27 08:31:41 +00:00
|
|
|
Actor::SetTextureRenderStates(); // set Actor-specified render states
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( mat.diffuse.m_bSphereMapped );
|
2005-01-04 05:38:44 +00:00
|
|
|
DrawMesh( i );
|
2004-08-09 00:46:42 +00:00
|
|
|
|
2005-01-04 05:38:44 +00:00
|
|
|
// render the additive texture
|
|
|
|
|
if( mat.alpha.GetCurrentTexture() )
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->SetTexture( 0, mat.alpha.GetCurrentTexture() );
|
2005-02-27 08:31:41 +00:00
|
|
|
Actor::SetTextureRenderStates(); // set Actor-specified render states
|
|
|
|
|
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( mat.alpha.m_bSphereMapped );
|
2005-01-04 05:38:44 +00:00
|
|
|
// UGLY: This overrides the Actor's BlendMode
|
|
|
|
|
DISPLAY->SetBlendMode( BLEND_ADD );
|
|
|
|
|
DISPLAY->SetTextureFiltering( true );
|
|
|
|
|
DrawMesh( i );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-01-28 08:53:40 +00:00
|
|
|
{
|
2005-04-26 20:18:51 +00:00
|
|
|
// render the diffuse texture with texture unit 1
|
|
|
|
|
DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() );
|
|
|
|
|
Actor::SetTextureRenderStates(); // set Actor-specified render states
|
|
|
|
|
DISPLAY->SetSphereEnvironmentMapping( mat.diffuse.m_bSphereMapped );
|
|
|
|
|
|
2005-01-04 05:38:44 +00:00
|
|
|
// render the additive texture with texture unit 2
|
|
|
|
|
if( mat.alpha.GetCurrentTexture() )
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->SetTexture( 1, mat.alpha.GetCurrentTexture() );
|
2005-02-27 08:31:41 +00:00
|
|
|
Actor::SetTextureRenderStates(); // set Actor-specified render states
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( mat.alpha.m_bSphereMapped );
|
2005-01-04 05:38:44 +00:00
|
|
|
DISPLAY->SetTextureModeAdd();
|
|
|
|
|
DISPLAY->SetTextureFiltering( true );
|
|
|
|
|
}
|
2005-04-26 08:11:30 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->SetTexture( 1, NULL );
|
2005-04-26 20:44:58 +00:00
|
|
|
|
|
|
|
|
// set current texture back to 0 or else texture transform applied above
|
|
|
|
|
// isn't used. Why?!?
|
|
|
|
|
DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() );
|
2005-04-26 08:11:30 +00:00
|
|
|
}
|
2005-01-04 05:38:44 +00:00
|
|
|
|
|
|
|
|
/* go */
|
|
|
|
|
DrawMesh( i );
|
2005-01-21 06:14:20 +00:00
|
|
|
|
|
|
|
|
// Turn off Environment mapping on tex unit 0. Is there a better way to reset?
|
|
|
|
|
DISPLAY->SetTexture( 0, NULL );
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( 0 );
|
2004-01-28 08:53:40 +00:00
|
|
|
}
|
2005-05-01 00:06:53 +00:00
|
|
|
|
|
|
|
|
if( vTexTranslate.x != 0 || vTexTranslate.y != 0 )
|
|
|
|
|
DISPLAY->TexturePopMatrix();
|
2003-12-24 21:07:50 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-02-05 23:42:38 +00:00
|
|
|
static const RageColor emissive( 0,0,0,0 );
|
|
|
|
|
static const RageColor ambient( 0.2f,0.2f,0.2f,1 );
|
|
|
|
|
static const RageColor diffuse( 0.7f,0.7f,0.7f,1 );
|
|
|
|
|
static const RageColor specular( 0.2f,0.2f,0.2f,1 );
|
|
|
|
|
static const float shininess = 1;
|
2004-06-18 11:02:40 +00:00
|
|
|
DISPLAY->SetMaterial( emissive, ambient, diffuse, specular, shininess );
|
2004-02-04 09:55:18 +00:00
|
|
|
DISPLAY->ClearAllTextures();
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( false );
|
2005-01-04 05:38:44 +00:00
|
|
|
DrawMesh( i );
|
2004-04-05 10:05:15 +00:00
|
|
|
}
|
|
|
|
|
|
2005-01-22 03:39:39 +00:00
|
|
|
DISPLAY->SetSphereEnvironmentMapping( false );
|
2005-01-04 05:38:44 +00:00
|
|
|
DISPLAY->SetBlendMode( BLEND_NORMAL );
|
2003-12-24 21:07:50 +00:00
|
|
|
}
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2003-04-27 05:14:27 +00:00
|
|
|
|
2003-09-23 05:39:24 +00:00
|
|
|
//////////////////////
|
|
|
|
|
// render the glow pass
|
|
|
|
|
//////////////////////
|
2003-10-07 04:26:14 +00:00
|
|
|
if( m_pTempState->glow.a > 0.0001f )
|
2003-09-23 05:39:24 +00:00
|
|
|
{
|
2003-12-24 21:07:50 +00:00
|
|
|
DISPLAY->SetTextureModeGlow();
|
|
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
for( unsigned i = 0; i < m_pGeometry->m_Meshes.size(); ++i )
|
2003-12-24 21:07:50 +00:00
|
|
|
{
|
2004-08-19 01:47:58 +00:00
|
|
|
const msMesh *pMesh = &m_pGeometry->m_Meshes[i];
|
2003-12-24 21:07:50 +00:00
|
|
|
|
|
|
|
|
// apply material
|
2004-07-31 16:56:47 +00:00
|
|
|
RageColor emissive = RageColor(0,0,0,0);
|
|
|
|
|
RageColor ambient = m_pTempState->glow;
|
|
|
|
|
RageColor diffuse = RageColor(0,0,0,0);
|
|
|
|
|
RageColor specular = RageColor(0,0,0,0);
|
2004-04-24 10:18:15 +00:00
|
|
|
float shininess = 1;
|
|
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
DISPLAY->SetMaterial( emissive, ambient, diffuse, specular, shininess );
|
2004-04-24 10:18:15 +00:00
|
|
|
DISPLAY->ClearAllTextures();
|
|
|
|
|
|
2003-12-24 21:07:50 +00:00
|
|
|
if( pMesh->nMaterialIndex != -1 )
|
|
|
|
|
{
|
|
|
|
|
msMaterial& mat = m_Materials[ pMesh->nMaterialIndex ];
|
2004-08-09 00:46:42 +00:00
|
|
|
DISPLAY->SetTexture( 0, mat.diffuse.GetCurrentTexture() );
|
2005-02-27 08:31:41 +00:00
|
|
|
Actor::SetTextureRenderStates(); // set Actor-specified render states
|
2003-12-24 21:07:50 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
DrawMesh( i );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-04-24 09:30:30 +00:00
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
void Model::DrawMesh( int i ) const
|
|
|
|
|
{
|
|
|
|
|
const msMesh *pMesh = &m_pGeometry->m_Meshes[i];
|
2004-04-24 09:30:30 +00:00
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
// apply mesh-specific bone (if any)
|
|
|
|
|
if( pMesh->nBoneIndex != -1 )
|
|
|
|
|
{
|
|
|
|
|
DISPLAY->PushMatrix();
|
2004-04-24 09:30:30 +00:00
|
|
|
|
2004-08-19 01:47:58 +00:00
|
|
|
const RageMatrix &mat = m_vpBones[pMesh->nBoneIndex].mFinal;
|
|
|
|
|
DISPLAY->PreMultMatrix( mat );
|
2003-09-23 05:39:24 +00:00
|
|
|
}
|
2004-08-19 01:47:58 +00:00
|
|
|
|
|
|
|
|
// Draw it
|
2004-08-19 06:24:41 +00:00
|
|
|
const RageCompiledGeometry* TempGeometry = m_pTempGeometry ? m_pTempGeometry : m_pGeometry->m_pCompiledGeometry;
|
2004-08-19 01:47:58 +00:00
|
|
|
DISPLAY->DrawCompiledGeometry( TempGeometry, i, m_pGeometry->m_Meshes );
|
|
|
|
|
|
|
|
|
|
if( pMesh->nBoneIndex != -1 )
|
|
|
|
|
DISPLAY->PopMatrix();
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2003-08-31 08:15:52 +00:00
|
|
|
void Model::SetDefaultAnimation( CString sAnimation, float fPlayRate )
|
2003-08-20 09:15:53 +00:00
|
|
|
{
|
|
|
|
|
m_sDefaultAnimation = sAnimation;
|
2003-08-31 08:15:52 +00:00
|
|
|
m_fDefaultAnimationRate = fPlayRate;
|
2003-08-20 09:15:53 +00:00
|
|
|
}
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2003-08-31 08:15:52 +00:00
|
|
|
void Model::PlayAnimation( CString sAniName, float fPlayRate )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
if( m_mapNameToAnimation.find(sAniName) == m_mapNameToAnimation.end() )
|
|
|
|
|
return;
|
2004-08-19 02:19:45 +00:00
|
|
|
|
2004-08-19 08:32:18 +00:00
|
|
|
const msAnimation *pNewAnimation = &m_mapNameToAnimation[sAniName];
|
2003-08-27 12:24:10 +00:00
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
m_fCurFrame = 0;
|
2003-08-31 08:15:52 +00:00
|
|
|
m_fCurAnimationRate = fPlayRate;
|
2003-08-27 12:24:10 +00:00
|
|
|
|
2005-09-03 23:08:43 +00:00
|
|
|
if( m_pCurAnimation == pNewAnimation )
|
2003-08-27 12:24:10 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_pCurAnimation = pNewAnimation;
|
2003-06-07 18:09:20 +00:00
|
|
|
|
|
|
|
|
// setup bones
|
2004-08-19 02:19:45 +00:00
|
|
|
unsigned nBoneCount = m_pCurAnimation->Bones.size();
|
2004-02-08 04:58:43 +00:00
|
|
|
m_vpBones.resize( nBoneCount );
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-08-19 02:19:45 +00:00
|
|
|
for( unsigned i = 0; i < nBoneCount; i++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 02:19:45 +00:00
|
|
|
const msBone *pBone = &m_pCurAnimation->Bones[i];
|
|
|
|
|
const RageVector3 &vRot = pBone->Rotation;
|
2003-12-24 12:30:41 +00:00
|
|
|
|
2004-02-08 04:58:43 +00:00
|
|
|
RageMatrixAngles( &m_vpBones[i].mRelative, vRot );
|
2003-12-24 12:30:41 +00:00
|
|
|
|
2004-02-08 04:58:43 +00:00
|
|
|
m_vpBones[i].mRelative.m[3][0] = pBone->Position[0];
|
|
|
|
|
m_vpBones[i].mRelative.m[3][1] = pBone->Position[1];
|
|
|
|
|
m_vpBones[i].mRelative.m[3][2] = pBone->Position[2];
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2003-06-07 18:09:20 +00:00
|
|
|
int nParentBone = m_pCurAnimation->FindBoneByName( pBone->szParentName );
|
2005-09-03 23:08:43 +00:00
|
|
|
if( nParentBone != -1 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-02-08 04:58:43 +00:00
|
|
|
RageMatrixMultiply( &m_vpBones[i].mAbsolute, &m_vpBones[nParentBone].mAbsolute, &m_vpBones[i].mRelative );
|
2003-12-24 12:30:41 +00:00
|
|
|
|
2004-02-08 04:58:43 +00:00
|
|
|
m_vpBones[i].mFinal = m_vpBones[i].mAbsolute;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2004-02-08 04:58:43 +00:00
|
|
|
m_vpBones[i].mAbsolute = m_vpBones[i].mRelative;
|
|
|
|
|
m_vpBones[i].mFinal = m_vpBones[i].mRelative;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-04-05 10:05:15 +00:00
|
|
|
// subtract out the bone's resting position
|
2005-09-03 23:08:43 +00:00
|
|
|
for( unsigned i = 0; i < m_pGeometry->m_Meshes.size(); ++i )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-02-08 09:04:23 +00:00
|
|
|
msMesh *pMesh = &m_pGeometry->m_Meshes[i];
|
2004-04-16 05:09:02 +00:00
|
|
|
vector<RageModelVertex> &Vertices = pMesh->Vertices;
|
2005-09-03 23:08:43 +00:00
|
|
|
for( unsigned j = 0; j < Vertices.size(); j++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-04-08 08:35:38 +00:00
|
|
|
// int nBoneIndex = (pMesh->nBoneIndex!=-1) ? pMesh->nBoneIndex : bone;
|
2004-04-16 05:09:02 +00:00
|
|
|
RageVector3 &pos = Vertices[j].p;
|
2004-05-11 20:35:21 +00:00
|
|
|
int8_t bone = Vertices[j].bone;
|
2004-08-19 02:19:45 +00:00
|
|
|
if( bone != -1 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-04-08 08:35:38 +00:00
|
|
|
pos[0] -= m_vpBones[bone].mAbsolute.m[3][0];
|
|
|
|
|
pos[1] -= m_vpBones[bone].mAbsolute.m[3][1];
|
|
|
|
|
pos[2] -= m_vpBones[bone].mAbsolute.m[3][2];
|
|
|
|
|
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector3 vTmp;
|
|
|
|
|
|
|
|
|
|
RageMatrix inverse;
|
2004-04-08 08:35:38 +00:00
|
|
|
RageMatrixTranspose( &inverse, &m_vpBones[bone].mAbsolute ); // transpose = inverse for rotation matrices
|
|
|
|
|
RageVec3TransformNormal( &vTmp, &pos, &inverse );
|
2003-12-24 12:30:41 +00:00
|
|
|
|
2004-04-08 08:35:38 +00:00
|
|
|
pos = vTmp;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-05-15 01:38:12 +00:00
|
|
|
|
2004-08-19 02:19:45 +00:00
|
|
|
/* Set up m_vpBones, just in case we're drawn without being Update()d. */
|
|
|
|
|
SetBones( m_pCurAnimation, m_fCurFrame, m_vpBones );
|
2004-09-17 01:32:57 +00:00
|
|
|
UpdateTempGeometry();
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
void Model::AdvanceFrame( float fDeltaTime )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-02-08 09:04:23 +00:00
|
|
|
if( m_pGeometry == NULL ||
|
|
|
|
|
m_pGeometry->m_Meshes.empty() ||
|
|
|
|
|
!m_pCurAnimation )
|
|
|
|
|
{
|
2003-06-07 18:09:20 +00:00
|
|
|
return; // bail early
|
2004-02-08 09:04:23 +00:00
|
|
|
}
|
2003-04-25 21:05:40 +00:00
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
// LOG->Trace( "m_fCurFrame = %f", m_fCurFrame );
|
2004-03-01 10:11:45 +00:00
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
m_fCurFrame += FRAMES_PER_SECOND * fDeltaTime * m_fCurAnimationRate;
|
|
|
|
|
if( m_fCurFrame >= m_pCurAnimation->nTotalFrames )
|
2003-08-20 09:15:53 +00:00
|
|
|
{
|
2004-02-23 00:23:52 +00:00
|
|
|
if( m_bRevertToDefaultAnimation && m_sDefaultAnimation != "" )
|
2003-08-20 09:15:53 +00:00
|
|
|
{
|
2003-08-31 08:15:52 +00:00
|
|
|
this->PlayAnimation( m_sDefaultAnimation, m_fDefaultAnimationRate );
|
2004-08-19 01:08:18 +00:00
|
|
|
/* XXX: add to m_fCurFrame the wrapover from the previous
|
|
|
|
|
* m_fCurFrame-m_pCurAnimation->nTotalFrames, so it doesn't skip */
|
2003-08-20 09:15:53 +00:00
|
|
|
}
|
2003-08-23 19:32:35 +00:00
|
|
|
else
|
2004-08-19 01:08:18 +00:00
|
|
|
m_fCurFrame -= m_pCurAnimation->nTotalFrames;
|
2003-08-20 09:15:53 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
SetBones( m_pCurAnimation, m_fCurFrame, m_vpBones );
|
2004-09-17 01:32:57 +00:00
|
|
|
UpdateTempGeometry();
|
2004-08-19 01:08:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Model::SetBones( const msAnimation* pAnimation, float fFrame, vector<myBone_t> &vpBones )
|
|
|
|
|
{
|
|
|
|
|
unsigned nBoneCount = pAnimation->Bones.size();
|
|
|
|
|
for( unsigned i = 0; i < nBoneCount; i++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 01:08:18 +00:00
|
|
|
const msBone *pBone = &pAnimation->Bones[i];
|
2003-04-25 21:05:40 +00:00
|
|
|
int nPositionKeyCount = pBone->PositionKeys.size();
|
|
|
|
|
int nRotationKeyCount = pBone->RotationKeys.size();
|
2004-08-19 01:08:18 +00:00
|
|
|
if( nPositionKeyCount == 0 && nRotationKeyCount == 0 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 01:08:18 +00:00
|
|
|
vpBones[i].mFinal = vpBones[i].mAbsolute;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-12-24 12:30:41 +00:00
|
|
|
RageVector3 vPos;
|
|
|
|
|
RageVector3 vRot;
|
2004-05-15 01:31:34 +00:00
|
|
|
|
2003-04-25 21:05:40 +00:00
|
|
|
//
|
2003-12-20 03:54:21 +00:00
|
|
|
// search for the adjacent position keys
|
2003-04-25 21:05:40 +00:00
|
|
|
//
|
2004-05-15 01:31:34 +00:00
|
|
|
const msPositionKey *pLastPositionKey = NULL, *pThisPositionKey = NULL;
|
2004-08-19 01:08:18 +00:00
|
|
|
for( int j = 0; j < nPositionKeyCount; j++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-05-15 01:31:34 +00:00
|
|
|
const msPositionKey *pPositionKey = &pBone->PositionKeys[j];
|
2004-08-19 01:08:18 +00:00
|
|
|
if( pPositionKey->fTime >= fFrame )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
|
|
|
|
pThisPositionKey = pPositionKey;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pLastPositionKey = pPositionKey;
|
|
|
|
|
}
|
2004-05-15 01:31:34 +00:00
|
|
|
if( pLastPositionKey != NULL && pThisPositionKey != NULL )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
|
|
|
|
float d = pThisPositionKey->fTime - pLastPositionKey->fTime;
|
2004-08-19 01:08:18 +00:00
|
|
|
float s = (fFrame - pLastPositionKey->fTime) / d;
|
2004-08-19 02:19:45 +00:00
|
|
|
vPos = pLastPositionKey->Position + (pThisPositionKey->Position - pLastPositionKey->Position) * s;
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2004-05-15 01:31:34 +00:00
|
|
|
else if( pLastPositionKey == NULL )
|
2003-12-24 12:30:41 +00:00
|
|
|
vPos = pThisPositionKey->Position;
|
2004-05-15 01:31:34 +00:00
|
|
|
else if( pThisPositionKey == NULL )
|
2003-12-24 12:30:41 +00:00
|
|
|
vPos = pLastPositionKey->Position;
|
2004-08-19 01:08:18 +00:00
|
|
|
|
2003-04-25 21:05:40 +00:00
|
|
|
//
|
2003-12-20 03:54:21 +00:00
|
|
|
// search for the adjacent rotation keys
|
2003-04-25 21:05:40 +00:00
|
|
|
//
|
2003-12-24 12:30:41 +00:00
|
|
|
RageMatrix m;
|
|
|
|
|
RageMatrixIdentity( &m );
|
2004-05-15 01:31:34 +00:00
|
|
|
const msRotationKey *pLastRotationKey = NULL, *pThisRotationKey = NULL;
|
2004-08-19 01:08:18 +00:00
|
|
|
for( int j = 0; j < nRotationKeyCount; j++ )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-05-15 01:31:34 +00:00
|
|
|
const msRotationKey *pRotationKey = &pBone->RotationKeys[j];
|
2004-08-19 01:08:18 +00:00
|
|
|
if( pRotationKey->fTime >= fFrame )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
|
|
|
|
pThisRotationKey = pRotationKey;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pLastRotationKey = pRotationKey;
|
|
|
|
|
}
|
2005-09-03 23:08:43 +00:00
|
|
|
if( pLastRotationKey != 0 && pThisRotationKey != 0 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 01:08:18 +00:00
|
|
|
const float s = SCALE( fFrame, pLastRotationKey->fTime, pThisRotationKey->fTime, 0, 1 );
|
2003-12-20 03:54:21 +00:00
|
|
|
|
2003-12-20 04:07:09 +00:00
|
|
|
RageVector4 q1, q2, q;
|
2004-08-19 02:19:45 +00:00
|
|
|
RageQuatFromHPR( &q1, pLastRotationKey->Rotation );
|
|
|
|
|
RageQuatFromHPR( &q2, pThisRotationKey->Rotation );
|
2003-12-20 04:07:09 +00:00
|
|
|
RageQuatSlerp( &q, q1, q2, s );
|
2003-12-20 03:54:21 +00:00
|
|
|
|
2003-12-24 12:30:41 +00:00
|
|
|
RageMatrixFromQuat( &m, q );
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2005-09-03 23:08:43 +00:00
|
|
|
else if( pLastRotationKey == 0 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 02:19:45 +00:00
|
|
|
vRot = pThisRotationKey->Rotation;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageMatrixAngles( &m, vRot );
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2005-09-03 23:08:43 +00:00
|
|
|
else if( pThisRotationKey == 0 )
|
2003-04-25 21:05:40 +00:00
|
|
|
{
|
2004-08-19 02:19:45 +00:00
|
|
|
vRot = pLastRotationKey->Rotation;
|
2003-12-24 12:30:41 +00:00
|
|
|
RageMatrixAngles( &m, vRot );
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
2003-12-24 12:30:41 +00:00
|
|
|
m.m[3][0] = vPos[0];
|
|
|
|
|
m.m[3][1] = vPos[1];
|
|
|
|
|
m.m[3][2] = vPos[2];
|
|
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
RageMatrixMultiply( &vpBones[i].mRelativeFinal, &vpBones[i].mRelative, &m );
|
2003-12-24 12:30:41 +00:00
|
|
|
|
2004-08-19 01:08:18 +00:00
|
|
|
int nParentBone = pAnimation->FindBoneByName( pBone->szParentName );
|
2004-05-15 01:31:34 +00:00
|
|
|
if( nParentBone == -1 )
|
2004-08-19 01:08:18 +00:00
|
|
|
vpBones[i].mFinal = vpBones[i].mRelativeFinal;
|
2003-04-25 21:05:40 +00:00
|
|
|
else
|
2004-08-19 01:08:18 +00:00
|
|
|
RageMatrixMultiply( &vpBones[i].mFinal, &vpBones[nParentBone].mFinal, &vpBones[i].mRelativeFinal );
|
2003-04-25 21:05:40 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-17 01:32:57 +00:00
|
|
|
void Model::UpdateTempGeometry()
|
|
|
|
|
{
|
|
|
|
|
if( m_pGeometry == NULL || m_pTempGeometry == NULL )
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for( unsigned i = 0; i < m_pGeometry->m_Meshes.size(); ++i )
|
|
|
|
|
{
|
|
|
|
|
const msMesh &origMesh = m_pGeometry->m_Meshes[i];
|
|
|
|
|
msMesh &tempMesh = m_vTempMeshes[i];
|
|
|
|
|
const vector<RageModelVertex> &origVertices = origMesh.Vertices;
|
|
|
|
|
vector<RageModelVertex> &tempVertices = tempMesh.Vertices;
|
|
|
|
|
for( unsigned j = 0; j < origVertices.size(); j++ )
|
|
|
|
|
{
|
|
|
|
|
RageVector3& tempPos = tempVertices[j].p;
|
|
|
|
|
RageVector3& tempNormal = tempVertices[j].n;
|
|
|
|
|
const RageVector3& originalPos = origVertices[j].p;
|
|
|
|
|
const RageVector3& originalNormal = origVertices[j].n;
|
|
|
|
|
int8_t bone = origVertices[j].bone;
|
|
|
|
|
|
|
|
|
|
if( bone == -1 )
|
|
|
|
|
{
|
|
|
|
|
tempNormal = originalNormal;
|
|
|
|
|
tempPos = originalPos;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
RageVec3TransformNormal( &tempNormal, &originalNormal, &m_vpBones[bone].mFinal );
|
|
|
|
|
RageVec3TransformCoord( &tempPos, &originalPos, &m_vpBones[bone].mFinal );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// send the new vertices to the graphics card
|
|
|
|
|
m_pTempGeometry->Change( m_vTempMeshes );
|
|
|
|
|
}
|
|
|
|
|
|
2003-04-25 21:05:40 +00:00
|
|
|
void Model::Update( float fDelta )
|
|
|
|
|
{
|
2003-04-27 05:14:27 +00:00
|
|
|
Actor::Update( fDelta );
|
2003-04-25 21:05:40 +00:00
|
|
|
AdvanceFrame( fDelta );
|
2003-08-20 09:15:53 +00:00
|
|
|
|
2004-08-19 00:42:31 +00:00
|
|
|
for( unsigned i = 0; i < m_Materials.size(); ++i )
|
2004-01-28 08:53:40 +00:00
|
|
|
{
|
2004-08-09 00:46:42 +00:00
|
|
|
m_Materials[i].diffuse.Update( fDelta );
|
|
|
|
|
m_Materials[i].alpha.Update( fDelta );
|
2004-01-28 08:53:40 +00:00
|
|
|
}
|
2003-05-11 07:23:47 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-09 00:46:42 +00:00
|
|
|
int Model::GetNumStates() const
|
|
|
|
|
{
|
|
|
|
|
int iMaxStates = 0;
|
|
|
|
|
FOREACH_CONST( msMaterial, m_Materials, m )
|
|
|
|
|
iMaxStates = max( iMaxStates, m->diffuse.GetNumStates() );
|
|
|
|
|
return iMaxStates;
|
|
|
|
|
}
|
|
|
|
|
|
2003-05-11 07:23:47 +00:00
|
|
|
void Model::SetState( int iNewState )
|
|
|
|
|
{
|
2004-08-09 00:46:42 +00:00
|
|
|
FOREACH( msMaterial, m_Materials, m )
|
2004-01-28 08:53:40 +00:00
|
|
|
{
|
2004-08-09 00:46:42 +00:00
|
|
|
m->diffuse.SetState( iNewState );
|
|
|
|
|
m->alpha.SetState( iNewState );
|
2004-01-28 08:53:40 +00:00
|
|
|
}
|
2003-05-11 07:23:47 +00:00
|
|
|
}
|
|
|
|
|
|
2004-08-09 00:46:42 +00:00
|
|
|
float Model::GetAnimationLengthSeconds() const
|
2003-05-11 07:23:47 +00:00
|
|
|
{
|
2004-08-09 00:46:42 +00:00
|
|
|
float fSeconds = 0;
|
|
|
|
|
FOREACH_CONST( msMaterial, m_Materials, m )
|
|
|
|
|
fSeconds = max( fSeconds, m->diffuse.GetAnimationLengthSeconds() );
|
|
|
|
|
return fSeconds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Model::SetSecondsIntoAnimation( float fSeconds )
|
|
|
|
|
{
|
|
|
|
|
FOREACH( msMaterial, m_Materials, m )
|
|
|
|
|
{
|
|
|
|
|
m->diffuse.SetSecondsIntoAnimation( fSeconds );
|
|
|
|
|
m->alpha.SetSecondsIntoAnimation( fSeconds );
|
|
|
|
|
}
|
2003-05-11 07:23:47 +00:00
|
|
|
}
|
2003-11-02 23:29:21 +00:00
|
|
|
|
2005-01-26 11:21:43 +00:00
|
|
|
/*
|
2004-12-03 05:19:46 +00:00
|
|
|
void Model::HandleCommand( const Command &command )
|
2003-11-02 23:29:21 +00:00
|
|
|
{
|
2004-12-03 05:19:46 +00:00
|
|
|
BeginHandleArgs;
|
2003-11-02 23:29:21 +00:00
|
|
|
|
2004-12-03 05:19:46 +00:00
|
|
|
const CString& sName = command.GetName();
|
2003-11-02 23:29:21 +00:00
|
|
|
if( sName=="play" )
|
2004-12-03 05:19:46 +00:00
|
|
|
{
|
|
|
|
|
PlayAnimation( sArg(1),fArg(2) );
|
|
|
|
|
}
|
2003-11-02 23:29:21 +00:00
|
|
|
else
|
|
|
|
|
{
|
2004-01-10 20:34:18 +00:00
|
|
|
Actor::HandleCommand( command );
|
2003-11-02 23:29:21 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-03 05:19:46 +00:00
|
|
|
EndHandleArgs;
|
2003-11-02 23:29:21 +00:00
|
|
|
}
|
2005-01-26 11:21:43 +00:00
|
|
|
*/
|
2004-06-08 00:47:53 +00:00
|
|
|
|
2005-01-14 10:23:22 +00:00
|
|
|
bool Model::MaterialsNeedNormals() const
|
|
|
|
|
{
|
|
|
|
|
FOREACH_CONST( msMaterial, m_Materials, m )
|
|
|
|
|
{
|
|
|
|
|
if( m->NeedsNormals() )
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-06-20 04:23:36 +00:00
|
|
|
// lua start
|
|
|
|
|
#include "LuaBinding.h"
|
|
|
|
|
|
2005-06-20 05:02:03 +00:00
|
|
|
class LunaModel: public Luna<Model>
|
2005-06-20 04:23:36 +00:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
LunaModel() { LUA->Register( Register ); }
|
|
|
|
|
|
|
|
|
|
static int playanimation( T* p, lua_State *L ) { p->PlayAnimation(SArg(1),FArg(2)); return 0; }
|
|
|
|
|
|
|
|
|
|
static void Register(lua_State *L)
|
|
|
|
|
{
|
2005-09-10 02:47:04 +00:00
|
|
|
ADD_METHOD( playanimation );
|
|
|
|
|
|
2005-06-20 04:23:36 +00:00
|
|
|
Luna<T>::Register( L );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2005-06-21 07:49:25 +00:00
|
|
|
LUA_REGISTER_DERIVED_CLASS( Model, Actor )
|
2005-06-20 04:23:36 +00:00
|
|
|
// lua end
|
|
|
|
|
|
2004-06-08 00:47:53 +00:00
|
|
|
/*
|
|
|
|
|
* (c) 2003-2004 Chris Danford
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|