Files
itgmania212121/stepmania/src/Model.cpp
T

941 lines
26 KiB
C++
Raw Normal View History

2003-04-25 21:05:40 +00:00
#include "global.h"
/*
-----------------------------------------------------------------------------
2003-05-11 07:23:47 +00:00
Class: Model
2003-04-25 21:05:40 +00:00
Desc: Types defined in msLib.h.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#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"
2003-05-11 07:23:47 +00:00
#include "IniFile.h"
2003-07-22 07:47:27 +00:00
#include "RageFile.h"
#include "RageLog.h"
#include "ActorUtil.h"
2003-12-02 20:46:21 +00:00
#include <errno.h>
2003-04-25 21:05:40 +00:00
2003-05-04 05:21:16 +00:00
const float FRAMES_PER_SECOND = 30;
const CString DEFAULT_ANIMATION_NAME = "default";
2003-05-04 05:21:16 +00:00
2003-04-25 21:05:40 +00:00
Model::Model ()
{
m_bTextureWrapping = true;
2003-11-18 20:33:18 +00:00
SetUseZBuffer( true );
m_pCurAnimation = NULL;
m_bRevertToDefaultAnimation = false;
m_fDefaultAnimationRate = 1;
m_fCurAnimationRate = 1;
2003-04-25 21:05:40 +00:00
}
Model::~Model ()
{
Clear ();
}
void Model::Clear ()
{
m_vpBones.clear();
m_Meshes.clear();
m_Materials.clear();
m_mapNameToAnimation.clear();
m_pCurAnimation = NULL;
2003-04-25 21:05:40 +00:00
}
#define THROW RageException::Throw( "Parse at line %d: '%s'", sLine.c_str() );
2003-05-04 05:21:16 +00:00
bool Model::LoadMilkshapeAscii( 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
Clear ();
CString sLine;
int iLineNum = 0;
2003-04-25 21:05:40 +00:00
char szName[MS_MAX_NAME];
int nFlags, nIndex, i, j;
2003-12-20 03:54:21 +00:00
RageVec3ClearBounds( m_vMins, m_vMaxs );
2003-04-25 21:05:40 +00:00
while( f.GetLine( sLine ) > 0 )
2003-04-25 21:05:40 +00:00
{
iLineNum++;
if (!strncmp (sLine, "//", 2))
2003-04-25 21:05:40 +00:00
continue;
int nFrame;
if (sscanf (sLine, "Frames: %d", &nFrame) == 1)
2003-04-25 21:05:40 +00:00
{
// ignore
// m_pModel->nTotalFrames = nFrame;
2003-04-25 21:05:40 +00:00
}
if (sscanf (sLine, "Frame: %d", &nFrame) == 1)
2003-04-25 21:05:40 +00:00
{
// ignore
// m_pModel->nFrame = nFrame;
2003-04-25 21:05:40 +00:00
}
int nNumMeshes = 0;
if (sscanf (sLine, "Meshes: %d", &nNumMeshes) == 1)
2003-04-25 21:05:40 +00:00
{
m_Meshes.resize( nNumMeshes );
2003-05-04 05:21:16 +00:00
for (i = 0; i < nNumMeshes; i++)
2003-04-25 21:05:40 +00:00
{
msMesh& mesh = m_Meshes[i];
2003-04-25 21:05:40 +00:00
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
// mesh: name, flags, material index
if (sscanf (sLine, "\"%[^\"]\" %d %d",szName, &nFlags, &nIndex) != 3)
THROW
2003-04-25 21:05:40 +00:00
strcpy( mesh.szName, szName );
2003-05-04 07:22:20 +00:00
// mesh.nFlags = nFlags;
2003-05-11 08:19:24 +00:00
mesh.nMaterialIndex = (byte)nIndex;
2003-04-25 21:05:40 +00:00
//
// vertices
//
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
int nNumVertices = 0;
if (sscanf (sLine, "%d", &nNumVertices) != 1)
THROW
2003-04-25 21:05:40 +00:00
2003-05-04 05:21:16 +00:00
mesh.Vertices.resize( nNumVertices );
2003-04-25 21:05:40 +00:00
for (j = 0; j < nNumVertices; j++)
{
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
RageVector3 Vertex;
RageVector2 uv;
if (sscanf (sLine, "%d %f %f %f %f %f %d",
2003-04-25 21:05:40 +00:00
&nFlags,
&Vertex[0], &Vertex[1], &Vertex[2],
&uv[0], &uv[1],
&nIndex
) != 7)
{
THROW
2003-04-25 21:05:40 +00:00
}
RageModelVertex& vertex = mesh.Vertices[j];
2003-05-04 05:21:16 +00:00
// vertex.nFlags = nFlags;
memcpy( vertex.p, Vertex, sizeof(vertex.p) );
memcpy( vertex.t, uv, sizeof(vertex.t) );
vertex.boneIndex = (byte)nIndex;
2003-12-20 03:54:21 +00:00
RageVec3AddToBounds( RageVector3(Vertex), m_vMins, m_vMaxs );
2003-04-25 21:05:40 +00:00
}
2003-05-04 05:21:16 +00:00
2003-04-25 21:05:40 +00:00
//
// normals
//
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
int nNumNormals = 0;
if (sscanf (sLine, "%d", &nNumNormals) != 1)
THROW
2003-05-04 05:21:16 +00:00
vector<RageVector3> Normals;
2003-05-04 05:21:16 +00:00
Normals.resize( nNumNormals );
2003-04-25 21:05:40 +00:00
for (j = 0; j < nNumNormals; j++)
{
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
RageVector3 Normal;
if (sscanf (sLine, "%f %f %f", &Normal[0], &Normal[1], &Normal[2]) != 3)
THROW
2003-04-25 21:05:40 +00:00
RageVec3Normalize( (RageVector3*)&Normal, (RageVector3*)&Normal );
2003-05-04 05:21:16 +00:00
Normals[j] = Normal;
2003-04-25 21:05:40 +00:00
}
2003-05-04 05:21:16 +00:00
2003-04-25 21:05:40 +00:00
//
// triangles
//
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
int nNumTriangles = 0;
if (sscanf (sLine, "%d", &nNumTriangles) != 1)
THROW
2003-04-25 21:05:40 +00:00
2003-05-04 05:21:16 +00:00
mesh.Triangles.resize( nNumTriangles );
2003-04-25 21:05:40 +00:00
for (j = 0; j < nNumTriangles; j++)
{
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
word nIndices[3];
word nNormalIndices[3];
if (sscanf (sLine, "%d %hd %hd %hd %hd %hd %hd %d",
2003-04-25 21:05:40 +00:00
&nFlags,
&nIndices[0], &nIndices[1], &nIndices[2],
&nNormalIndices[0], &nNormalIndices[1], &nNormalIndices[2],
&nIndex
) != 8)
{
THROW
2003-04-25 21:05:40 +00:00
}
2003-05-04 05:21:16 +00:00
// deflate the normals into vertices
for( int k=0; k<3; k++ )
{
RageModelVertex& vertex = mesh.Vertices[ nIndices[k] ];
RageVector3& normal = Normals[ nNormalIndices[k] ];
vertex.n = normal;
2003-05-04 05:21:16 +00:00
}
msTriangle& Triangle = mesh.Triangles[j];
// Triangle.nFlags = nFlags;
2003-04-25 21:05:40 +00:00
memcpy( &Triangle.nVertexIndices, nIndices, sizeof(Triangle.nVertexIndices) );
2003-05-04 05:21:16 +00:00
// Triangle.nSmoothingGroup = nIndex;
2003-04-25 21:05:40 +00:00
}
}
}
//
// materials
//
int nNumMaterials = 0;
if (sscanf (sLine, "Materials: %d", &nNumMaterials) == 1)
2003-04-25 21:05:40 +00:00
{
m_Materials.resize( nNumMaterials );
2003-05-04 05:21:16 +00:00
int i;
2003-10-21 05:14:21 +00:00
char szName[256];
2003-04-25 21:05:40 +00:00
for (i = 0; i < nNumMaterials; i++)
2003-04-25 21:05:40 +00:00
{
msMaterial& Material = m_Materials[i];
2003-04-25 21:05:40 +00:00
// name
if( f.GetLine( sLine ) <= 0 )
THROW
if (sscanf (sLine, "\"%[^\"]\"", szName) != 1)
THROW
2003-04-25 21:05:40 +00:00
strcpy( Material.szName, szName );
// ambient
if( f.GetLine( sLine ) <= 0 )
THROW
RageVector4 Ambient;
if (sscanf (sLine, "%f %f %f %f", &Ambient[0], &Ambient[1], &Ambient[2], &Ambient[3]) != 4)
THROW
2003-04-25 21:05:40 +00:00
memcpy( &Material.Ambient, &Ambient, sizeof(Material.Ambient) );
// diffuse
if( f.GetLine( sLine ) <= 0 )
THROW
RageVector4 Diffuse;
if (sscanf (sLine, "%f %f %f %f", &Diffuse[0], &Diffuse[1], &Diffuse[2], &Diffuse[3]) != 4)
THROW
2003-04-25 21:05:40 +00:00
memcpy( &Material.Diffuse, &Diffuse, sizeof(Material.Diffuse) );
// specular
if( f.GetLine( sLine ) <= 0 )
THROW
RageVector4 Specular;
if (sscanf (sLine, "%f %f %f %f", &Specular[0], &Specular[1], &Specular[2], &Specular[3]) != 4)
THROW
2003-04-25 21:05:40 +00:00
memcpy( &Material.Specular, &Specular, sizeof(Material.Specular) );
// emissive
if( f.GetLine( sLine ) <= 0 )
THROW
RageVector4 Emissive;
if (sscanf (sLine, "%f %f %f %f", &Emissive[0], &Emissive[1], &Emissive[2], &Emissive[3]) != 4)
THROW
2003-04-25 21:05:40 +00:00
memcpy( &Material.Emissive, &Emissive, sizeof(Material.Emissive) );
// shininess
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
float fShininess;
if (sscanf (sLine, "%f", &fShininess) != 1)
THROW
2003-04-25 21:05:40 +00:00
Material.fShininess = fShininess;
// transparency
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
float fTransparency;
if (sscanf (sLine, "%f", &fTransparency) != 1)
THROW
2003-05-04 05:21:16 +00:00
Material.fTransparency = fTransparency;
2003-04-25 21:05:40 +00:00
// diffuse texture
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-27 05:14:27 +00:00
strcpy (szName, "");
sscanf (sLine, "\"%[^\"]\"", szName);
2003-04-25 21:05:40 +00:00
strcpy( Material.szDiffuseTexture, szName );
if( strcmp(Material.szDiffuseTexture, "")!=0 )
{
2003-09-16 01:12:20 +00:00
CString sTexturePath = sDir + Material.szDiffuseTexture;
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-04-25 21:05:40 +00:00
// alpha texture
if( f.GetLine( sLine ) <= 0 )
THROW
2003-04-25 21:05:40 +00:00
strcpy (szName, "");
sscanf (sLine, "\"%[^\"]\"", szName);
2003-04-25 21:05:40 +00:00
strcpy( Material.szAlphaTexture, szName );
2004-01-28 08:53:40 +00:00
if( strcmp(Material.szAlphaTexture, "")!=0 )
{
CString sTexturePath = sDir + Material.szAlphaTexture;
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-04-25 21:05:40 +00:00
LoadMilkshapeAsciiBones( DEFAULT_ANIMATION_NAME, sPath );
2003-05-04 05:21:16 +00:00
//
// Setup temp vertices (if necessary)
//
bUseTempVertices = m_mapNameToAnimation[DEFAULT_ANIMATION_NAME].Bones.size() > 0; // if there are no bones, then there's no reason to use temp vertices
if( bUseTempVertices )
{
m_vTempVerticesByMesh.resize( m_Meshes.size() );
for (i = 0; i < (int)m_Meshes.size(); i++)
{
msMesh& Mesh = m_Meshes[i];
m_vTempVerticesByMesh[i].resize( Mesh.Vertices.size() );
}
}
2003-05-04 05:21:16 +00:00
return true;
}
bool Model::LoadMilkshapeAsciiBones( CString sAniName, CString sPath )
2003-05-04 05:21:16 +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-05-04 05:21:16 +00:00
2003-12-04 23:05:23 +00:00
RageFile f;
if ( !f.Open(sPath) )
RageException::Throw( "Model:: Could not open \"%s\": %s", sPath.c_str(), f.GetError().c_str() );
2003-05-04 05:21:16 +00:00
CString sLine;
int iLineNum = 0;
2003-05-04 05:21:16 +00:00
int nFlags, j;
while( f.GetLine( sLine ) > 0 )
2003-05-04 05:21:16 +00:00
{
iLineNum++;
if (!strncmp (sLine, "//", 2))
2003-05-04 05:21:16 +00:00
continue;
//
// bones
//
int nNumBones = 0;
if (sscanf (sLine, "Bones: %d", &nNumBones) == 1)
2003-05-04 05:21:16 +00:00
{
m_mapNameToAnimation[sAniName] = msAnimation();
msAnimation &Animation = m_mapNameToAnimation[sAniName];
2003-05-04 05:21:16 +00:00
int i;
char szName[MS_MAX_NAME];
Animation.Bones.resize( nNumBones );
2003-05-04 05:21:16 +00:00
for (i = 0; i < nNumBones; i++)
2003-05-04 05:21:16 +00:00
{
msBone& Bone = Animation.Bones[i];
2003-05-04 05:21:16 +00:00
// name
if( f.GetLine( sLine ) <= 0 )
2003-05-04 05:21:16 +00:00
{
THROW;
2003-05-04 05:21:16 +00:00
}
if (sscanf (sLine, "\"%[^\"]\"", szName) != 1)
2003-05-04 05:21:16 +00:00
{
THROW;
2003-05-04 05:21:16 +00:00
}
strcpy( Bone.szName, szName );
// parent
if( f.GetLine( sLine ) <= 0 )
2003-05-04 05:21:16 +00:00
{
THROW;
2003-05-04 05:21:16 +00:00
}
strcpy (szName, "");
sscanf (sLine, "\"%[^\"]\"", szName);
2003-05-04 05:21:16 +00:00
strcpy( Bone.szParentName, szName );
// flags, position, rotation
RageVector3 Position, Rotation;
if( f.GetLine( sLine ) <= 0 )
THROW;
if (sscanf (sLine, "%d %f %f %f %f %f %f",
2003-05-04 05:21:16 +00:00
&nFlags,
&Position[0], &Position[1], &Position[2],
&Rotation[0], &Rotation[1], &Rotation[2]) != 7)
2003-05-04 05:21:16 +00:00
{
THROW;
2003-05-04 05:21:16 +00:00
}
Bone.nFlags = nFlags;
memcpy( &Bone.Position, &Position, sizeof(Bone.Position) );
memcpy( &Bone.Rotation, &Rotation, sizeof(Bone.Rotation) );
float fTime;
// position key count
if( f.GetLine( sLine ) <= 0 )
THROW;
2003-05-04 05:21:16 +00:00
int nNumPositionKeys = 0;
if (sscanf (sLine, "%d", &nNumPositionKeys) != 1)
THROW;
2003-05-04 05:21:16 +00:00
Bone.PositionKeys.resize( nNumPositionKeys );
for (j = 0; j < nNumPositionKeys; j++)
{
if( f.GetLine( sLine ) <= 0 )
THROW;
if (sscanf (sLine, "%f %f %f %f", &fTime, &Position[0], &Position[1], &Position[2]) != 4)
THROW;
2003-05-04 05:21:16 +00:00
msPositionKey key;
key.fTime = fTime;
key.Position = RageVector3( Position[0], Position[1], Position[2] );
2003-05-04 05:21:16 +00:00
Bone.PositionKeys[j] = key;
}
// rotation key count
if( f.GetLine( sLine ) <= 0 )
THROW;
2003-05-04 05:21:16 +00:00
int nNumRotationKeys = 0;
if (sscanf (sLine, "%d", &nNumRotationKeys) != 1)
THROW;
2003-05-04 05:21:16 +00:00
Bone.RotationKeys.resize( nNumRotationKeys );
for (j = 0; j < nNumRotationKeys; j++)
{
if( f.GetLine( sLine ) <= 0 )
THROW;
if (sscanf (sLine, "%f %f %f %f", &fTime, &Rotation[0], &Rotation[1], &Rotation[2]) != 4)
THROW;
2003-05-04 05:21:16 +00:00
msRotationKey key;
key.fTime = fTime;
key.Rotation = RageVector3( Rotation[0], Rotation[1], Rotation[2] );
2003-05-04 05:21:16 +00:00
Bone.RotationKeys[j] = key;
}
}
// Ignore "Frames:" in file. Calculate it ourself
Animation.nTotalFrames = 0;
for ( i = 0; i < (int)Animation.Bones.size(); i++)
{
msBone& Bone = Animation.Bones[i];
for( int j=0; j<(int)Bone.PositionKeys.size(); j++ )
{
Animation.nTotalFrames = max( Animation.nTotalFrames, (int)Bone.PositionKeys[j].fTime+1 );
Animation.nTotalFrames = max( Animation.nTotalFrames, (int)Bone.RotationKeys[j].fTime+1 );
}
}
PlayAnimation( sAniName );
2003-05-04 05:21:16 +00:00
}
}
2003-04-25 21:05:40 +00:00
return true;
}
void Model::DrawPrimitives()
{
if(m_Meshes.empty())
return; // bail early
2003-04-25 21:05:40 +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 )
return;
2003-05-22 05:28:37 +00:00
Actor::SetRenderStates(); // set Actor-specified render states
2003-05-09 04:42:04 +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
//
// process vertices
//
if( bUseTempVertices )
2003-04-25 21:05:40 +00:00
{
for (int i = 0; i < (int)m_Meshes.size(); i++)
2003-04-25 21:05:40 +00:00
{
msMesh *pMesh = &m_Meshes[i];
RageModelVertexVector& TempVertices = m_vTempVerticesByMesh[i];
for (int j = 0; j < (int)pMesh->Vertices.size(); j++)
2003-05-04 07:22:20 +00:00
{
RageModelVertex& tempVert = TempVertices[j];
RageModelVertex& originalVert = pMesh->Vertices[j];
2003-05-11 07:23:47 +00:00
tempVert.t = originalVert.t;
if( originalVert.boneIndex == -1 )
{
tempVert.n = originalVert.n;
tempVert.p = originalVert.p;
}
else
{
int bone = originalVert.boneIndex;
RageVec3TransformNormal( &tempVert.n, &originalVert.n, &m_vpBones[bone].mFinal );
RageVec3TransformCoord( &tempVert.p, &originalVert.p, &m_vpBones[bone].mFinal );
}
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();
for (int i = 0; i < (int)m_Meshes.size(); i++)
{
msMesh *pMesh = &m_Meshes[i];
RageModelVertexVector& TempVertices = bUseTempVertices ? m_vTempVerticesByMesh[i] : pMesh->Vertices;
2003-12-24 21:07:50 +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-01-28 08:53:40 +00:00
// apply material
2003-12-24 21:07:50 +00:00
msMaterial& mat = m_Materials[ pMesh->nMaterialIndex ];
RageColor Emissive = mat.Emissive;
RageColor Ambient = mat.Ambient;
RageColor Diffuse = mat.Diffuse;
Emissive *= m_pTempState->diffuse[0];
Ambient *= m_pTempState->diffuse[0];
Diffuse *= m_pTempState->diffuse[0];
2003-12-24 21:07:50 +00:00
DISPLAY->SetMaterial(
Emissive,
Ambient,
Diffuse,
mat.Specular,
mat.fShininess );
2004-01-28 08:53:40 +00:00
// render the first pass with texture 1
DISPLAY->SetTexture( 0, mat.diffuse.ani.GetCurrentTexture() );
2004-01-28 08:53:40 +00:00
DISPLAY->SetSphereEnironmentMapping( mat.diffuse.bSphereMapped );
// UGLY: This overrides the Actor's BlendMode
// DISPLAY->SetBlendMode( mat.diffuse.blendMode );
2004-01-28 08:53:40 +00:00
// render the second pass with texture 2
if( mat.alpha.ani.GetCurrentTexture() )
{
DISPLAY->SetTexture( 1, mat.alpha.ani.GetCurrentTexture() );
2004-01-28 08:53:40 +00:00
DISPLAY->SetSphereEnironmentMapping( mat.alpha.bSphereMapped );
// UGLY: This overrides the Actor's BlendMode
DISPLAY->SetTextureModeAdd();
2004-01-28 08:53:40 +00:00
}
DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 );
2004-01-28 08:53:40 +00:00
DISPLAY->SetSphereEnironmentMapping( false );
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;
2003-12-24 21:07:50 +00:00
DISPLAY->SetMaterial(
emissive,
ambient,
diffuse,
specular,
shininess );
DISPLAY->ClearAllTextures();
2004-01-06 19:54:13 +00:00
DISPLAY->SetSphereEnironmentMapping( false );
2004-01-28 08:53:40 +00:00
DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 );
2003-12-24 21:07:50 +00:00
}
}
2003-04-25 21:05:40 +00:00
}
2003-04-27 05:14:27 +00:00
//////////////////////
// render the glow pass
//////////////////////
2003-10-07 04:26:14 +00:00
if( m_pTempState->glow.a > 0.0001f )
{
2003-12-24 21:07:50 +00:00
DISPLAY->SetTextureModeGlow();
for (int i = 0; i < (int)m_Meshes.size(); i++)
{
msMesh *pMesh = &m_Meshes[i];
RageModelVertexVector& TempVertices = m_vTempVerticesByMesh[i];
2003-12-24 21:07:50 +00:00
// apply material
if( pMesh->nMaterialIndex != -1 )
{
msMaterial& mat = m_Materials[ pMesh->nMaterialIndex ];
RageColor Emissive = mat.Emissive;
RageColor Ambient = mat.Ambient;
RageColor Diffuse = mat.Diffuse;
Emissive = m_pTempState->glow;
Ambient = m_pTempState->glow;
Diffuse = m_pTempState->glow;
DISPLAY->SetMaterial(
Emissive,
Ambient,
Diffuse,
mat.Specular,
mat.fShininess );
DISPLAY->ClearAllTextures();
DISPLAY->SetTexture( 0, mat.diffuse.ani.GetCurrentTexture() );
2003-12-24 21:07:50 +00:00
}
else
{
RageColor emissive = m_pTempState->glow;
RageColor ambient = m_pTempState->glow;
RageColor diffuse = m_pTempState->glow;
RageColor specular = m_pTempState->glow;
float shininess = 1;
DISPLAY->SetMaterial(
emissive,
ambient,
diffuse,
specular,
shininess );
DISPLAY->ClearAllTextures();
2003-12-24 21:07:50 +00:00
}
DISPLAY->DrawIndexedTriangles( &TempVertices[0], pMesh->Vertices.size(), (Uint16*)&pMesh->Triangles[0], pMesh->Triangles.size()*3 );
}
}
2003-04-25 21:05:40 +00:00
}
void Model::SetDefaultAnimation( CString sAnimation, float fPlayRate )
{
m_sDefaultAnimation = sAnimation;
m_fDefaultAnimationRate = fPlayRate;
}
2003-04-25 21:05:40 +00:00
void Model::PlayAnimation( CString sAniName, float fPlayRate )
2003-04-25 21:05:40 +00:00
{
msAnimation *pNewAnimation = NULL;
if( m_mapNameToAnimation.find(sAniName) == m_mapNameToAnimation.end() )
return;
else
pNewAnimation = &m_mapNameToAnimation[sAniName];
m_fCurrFrame = 0;
m_fCurAnimationRate = fPlayRate;
if ( m_pCurAnimation == pNewAnimation )
return;
m_pCurAnimation = pNewAnimation;
// setup bones
int nBoneCount = (int)m_pCurAnimation->Bones.size();
m_vpBones.resize( nBoneCount );
2003-04-25 21:05:40 +00:00
int i, j;
for (i = 0; i < nBoneCount; i++)
{
msBone *pBone = &m_pCurAnimation->Bones[i];
RageVector3 vRot;
vRot[0] = pBone->Rotation[0] * 180 / (float) PI;
vRot[1] = pBone->Rotation[1] * 180 / (float) PI;
vRot[2] = pBone->Rotation[2] * 180 / (float) PI;
RageMatrixAngles( &m_vpBones[i].mRelative, vRot );
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
int nParentBone = m_pCurAnimation->FindBoneByName( pBone->szParentName );
2003-04-25 21:05:40 +00:00
if (nParentBone != -1)
{
RageMatrixMultiply( &m_vpBones[i].mAbsolute, &m_vpBones[nParentBone].mAbsolute, &m_vpBones[i].mRelative );
m_vpBones[i].mFinal = m_vpBones[i].mAbsolute;
2003-04-25 21:05:40 +00:00
}
else
{
m_vpBones[i].mAbsolute = m_vpBones[i].mRelative;
m_vpBones[i].mFinal = m_vpBones[i].mRelative;
2003-04-25 21:05:40 +00:00
}
}
for (i = 0; i < (int)m_Meshes.size(); i++)
2003-04-25 21:05:40 +00:00
{
msMesh *pMesh = &m_Meshes[i];
2003-04-25 21:05:40 +00:00
for (j = 0; j < (int)pMesh->Vertices.size(); j++)
{
RageModelVertex *pVertex = &pMesh->Vertices[j];
if (pVertex->boneIndex != -1)
2003-04-25 21:05:40 +00:00
{
pVertex->p[0] -= m_vpBones[pVertex->boneIndex].mAbsolute.m[3][0];
pVertex->p[1] -= m_vpBones[pVertex->boneIndex].mAbsolute.m[3][1];
pVertex->p[2] -= m_vpBones[pVertex->boneIndex].mAbsolute.m[3][2];
RageVector3 vTmp;
RageMatrix inverse;
RageMatrixTranspose( &inverse, &m_vpBones[pVertex->boneIndex].mAbsolute ); // transpose = inverse for rotation matrices
RageVec3TransformNormal( &vTmp, &pVertex->p, &inverse );
pVertex->p = vTmp;
2003-04-25 21:05:40 +00:00
}
}
}
}
float Model::GetCurFrame() { return m_fCurrFrame; };
void Model::SetFrame( float fNewFrame )
{
m_fCurrFrame = fNewFrame;
}
2003-04-25 21:05:40 +00:00
void
Model::AdvanceFrame (float dt)
{
if( m_Meshes.empty() || !m_pCurAnimation )
return; // bail early
2003-04-25 21:05:40 +00:00
m_fCurrFrame += FRAMES_PER_SECOND * dt * m_fCurAnimationRate;
if (m_fCurrFrame >= (float)m_pCurAnimation->nTotalFrames)
{
if( (m_bRevertToDefaultAnimation) && (m_sDefaultAnimation != "") )
{
this->PlayAnimation( m_sDefaultAnimation, m_fDefaultAnimationRate );
}
2003-08-23 19:32:35 +00:00
else
{
m_fCurrFrame = 0.0f;
}
}
2003-04-25 21:05:40 +00:00
int nBoneCount = (int)m_pCurAnimation->Bones.size();
2003-04-25 21:05:40 +00:00
int i, j;
for (i = 0; i < nBoneCount; i++)
{
msBone *pBone = &m_pCurAnimation->Bones[i];
2003-04-25 21:05:40 +00:00
int nPositionKeyCount = pBone->PositionKeys.size();
int nRotationKeyCount = pBone->RotationKeys.size();
if (nPositionKeyCount == 0 && nRotationKeyCount == 0)
{
m_vpBones[i].mFinal = m_vpBones[i].mAbsolute;
2003-04-25 21:05:40 +00:00
}
else
{
RageVector3 vPos;
RageVector3 vRot;
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
//
msPositionKey *pLastPositionKey = 0, *pThisPositionKey = 0;
for (j = 0; j < nPositionKeyCount; j++)
{
msPositionKey *pPositionKey = &pBone->PositionKeys[j];
if (pPositionKey->fTime >= m_fCurrFrame)
{
pThisPositionKey = pPositionKey;
break;
}
pLastPositionKey = pPositionKey;
}
if (pLastPositionKey != 0 && pThisPositionKey != 0)
{
float d = pThisPositionKey->fTime - pLastPositionKey->fTime;
float s = (m_fCurrFrame - pLastPositionKey->fTime) / d;
vPos[0] = pLastPositionKey->Position[0] + (pThisPositionKey->Position[0] - pLastPositionKey->Position[0]) * s;
vPos[1] = pLastPositionKey->Position[1] + (pThisPositionKey->Position[1] - pLastPositionKey->Position[1]) * s;
vPos[2] = pLastPositionKey->Position[2] + (pThisPositionKey->Position[2] - pLastPositionKey->Position[2]) * s;
}
else if (pLastPositionKey == 0)
{
vPos = pThisPositionKey->Position;
2003-04-25 21:05:40 +00:00
}
else if (pThisPositionKey == 0)
{
vPos = pLastPositionKey->Position;
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
//
RageMatrix m;
RageMatrixIdentity( &m );
2003-04-25 21:05:40 +00:00
msRotationKey *pLastRotationKey = 0, *pThisRotationKey = 0;
for (j = 0; j < nRotationKeyCount; j++)
{
msRotationKey *pRotationKey = &pBone->RotationKeys[j];
if (pRotationKey->fTime >= m_fCurrFrame)
{
pThisRotationKey = pRotationKey;
break;
}
pLastRotationKey = pRotationKey;
}
if (pLastRotationKey != 0 && pThisRotationKey != 0)
{
2003-12-20 04:07:09 +00:00
const float s = SCALE( m_fCurrFrame, 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;
RageQuatFromHPR( &q1, RageVector3(pLastRotationKey->Rotation) * (180 / PI) );
RageQuatFromHPR( &q2, RageVector3(pThisRotationKey->Rotation) * (180 / PI) );
RageQuatSlerp( &q, q1, q2, s );
2003-12-20 03:54:21 +00:00
RageMatrixFromQuat( &m, q );
2003-04-25 21:05:40 +00:00
}
else if (pLastRotationKey == 0)
{
vRot[0] = pThisRotationKey->Rotation[0] * 180 / (float) PI;
vRot[1] = pThisRotationKey->Rotation[1] * 180 / (float) PI;
vRot[2] = pThisRotationKey->Rotation[2] * 180 / (float) PI;
RageMatrixAngles( &m, vRot );
2003-04-25 21:05:40 +00:00
}
else if (pThisRotationKey == 0)
{
vRot[0] = pLastRotationKey->Rotation[0] * 180 / (float) PI;
vRot[1] = pLastRotationKey->Rotation[1] * 180 / (float) PI;
vRot[2] = pLastRotationKey->Rotation[2] * 180 / (float) PI;
RageMatrixAngles( &m, vRot );
2003-04-25 21:05:40 +00:00
}
m.m[3][0] = vPos[0];
m.m[3][1] = vPos[1];
m.m[3][2] = vPos[2];
RageMatrixMultiply( &m_vpBones[i].mRelativeFinal, &m_vpBones[i].mRelative, &m );
int nParentBone = m_pCurAnimation->FindBoneByName( pBone->szParentName );
2003-04-25 21:05:40 +00:00
if (nParentBone == -1)
{
m_vpBones[i].mFinal = m_vpBones[i].mRelativeFinal;
2003-04-25 21:05:40 +00:00
}
else
{
RageMatrixMultiply( &m_vpBones[i].mFinal, &m_vpBones[nParentBone].mFinal, &m_vpBones[i].mRelativeFinal );
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 );
for( int i=0; i<(int)m_Materials.size(); i++ )
2004-01-28 08:53:40 +00:00
{
m_Materials[i].diffuse.ani.Update( fDelta );
m_Materials[i].alpha.ani.Update( fDelta );
}
2003-05-11 07:23:47 +00:00
}
void Model::SetState( int iNewState )
{
for( int i=0; i<(int)m_Materials.size(); i++ )
2004-01-28 08:53:40 +00:00
{
m_Materials[i].diffuse.ani.SetState( iNewState );
m_Materials[i].alpha.ani.SetState( iNewState );
}
2003-05-11 07:23:47 +00:00
}
int Model::GetNumStates()
{
int iMaxStates = 0;
for( int i=0; i<(int)m_Materials.size(); i++ )
2004-01-28 08:53:40 +00:00
iMaxStates = max( iMaxStates, m_Materials[i].diffuse.ani.GetNumStates() );
2003-05-11 07:23:47 +00:00
return iMaxStates;
}
void Model::HandleCommand( const ParsedCommand &command )
{
HandleParams;
/* XXX: It would be very useful to be able to tween animations, eg:
*
* play,Dance,1;sleep,2;linear,.5;play,Collapse,1
*
* to play "Dance" for two seconds, then tween to playing "Collapse" over half
* a second, with the tween percentage weighting the animations.
*
* Also, being able to queue animations cleanly without knowing the exact duration
* of the animation, eg:
*
* play,Dance,1;finishanim;play,Collapse,1
*
* to play "Dance", and then play "Collapse" when "Dance" finishes. (In this case,
* Dance would presumably end on the same keyframe that Collapse begins on, since
* it isn't queuing a tween.)
*
* We need more architecture for this, so we can put custom items in the Actor
* tween queue.
*/
const CString& sName = sParam(0);
if( sName=="play" )
PlayAnimation( sParam(1),fParam(2) );
else
{
Actor::HandleCommand( command );
return;
}
CheckHandledParams;
}