initial
This commit is contained in:
88
studiorender/_vpc_/manifest_studiorender/win32/manifest.txt
Normal file
88
studiorender/_vpc_/manifest_studiorender/win32/manifest.txt
Normal file
@@ -0,0 +1,88 @@
|
||||
// ----------------------------------------- //
|
||||
// File generated by VPC //
|
||||
// ----------------------------------------- //
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\common\debug_dll_check.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\flexrenderdata.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\flexrenderdata.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\flexrenderdata.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\public\tier0\memoverride.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studio.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studio.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studio.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiodecal.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodecal.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodecal.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw_computeflexedvertex.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw_computeflexedvertex.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiodraw_computeflexedvertex.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studioflex.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studioflex.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studioflex.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiogettriangles.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiogettriangles.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiogettriangles.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiolight.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiolight.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiolight.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd_patches.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd_patches.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\r_studiosubd_patches.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\studiorender.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\studiorender.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\studiorender.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
Source file: F:\csgo_64\cstrike15_src\studiorender\studiorendercontext.cpp
|
||||
Debug output file: F:\csgo_64\cstrike15_src\studiorender\studiorendercontext.cpp
|
||||
Release output file: F:\csgo_64\cstrike15_src\studiorender\studiorendercontext.cpp
|
||||
Containing unity file:
|
||||
PCH file:
|
||||
|
||||
243
studiorender/flexrenderdata.cpp
Normal file
243
studiorender/flexrenderdata.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
//========= Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "flexrenderdata.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CCachedRenderData::CCachedRenderData() : m_CurrentTag(0), m_pFirstFlexIndex(0),
|
||||
m_pFirstWorldIndex(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
int i;
|
||||
float val = VEC_T_NAN;
|
||||
for( i = 0; i < MAXSTUDIOFLEXVERTS; i++ )
|
||||
{
|
||||
m_pFlexVerts[i].m_Position[0] = val;
|
||||
m_pFlexVerts[i].m_Position[1] = val;
|
||||
m_pFlexVerts[i].m_Position[2] = val;
|
||||
m_pFlexVerts[i].m_Normal[0] = val;
|
||||
m_pFlexVerts[i].m_Normal[1] = val;
|
||||
m_pFlexVerts[i].m_Normal[2] = val;
|
||||
|
||||
m_pThinFlexVerts[i].m_Position[0] = val;
|
||||
m_pThinFlexVerts[i].m_Position[1] = val;
|
||||
m_pThinFlexVerts[i].m_Position[2] = val;
|
||||
m_pThinFlexVerts[i].m_Normal[0] = val;
|
||||
m_pThinFlexVerts[i].m_Normal[1] = val;
|
||||
m_pThinFlexVerts[i].m_Normal[2] = val;
|
||||
|
||||
m_pFlexVerts[i].m_TangentS[0] = val;
|
||||
m_pFlexVerts[i].m_TangentS[1] = val;
|
||||
m_pFlexVerts[i].m_TangentS[2] = val;
|
||||
m_pFlexVerts[i].m_TangentS[3] = val;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this before rendering the model
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CCachedRenderData::StartModel()
|
||||
{
|
||||
++m_CurrentTag;
|
||||
m_IndexCount = 0;
|
||||
m_FlexVertexCount = 0;
|
||||
m_ThinFlexVertexCount = 0;
|
||||
m_WorldVertexCount = 0;
|
||||
m_pFirstFlexIndex = 0;
|
||||
m_pFirstThinFlexIndex = 0;
|
||||
m_pFirstWorldIndex = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to hook ourselves into a particular body part, model, and mesh
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CCachedRenderData::SetBodyPart( int bodypart )
|
||||
{
|
||||
m_Body = bodypart;
|
||||
m_CacheDict.EnsureCount(m_Body+1);
|
||||
m_Model = m_Mesh = -1;
|
||||
m_pFirstFlexIndex = 0;
|
||||
m_pFirstThinFlexIndex = 0;
|
||||
m_pFirstWorldIndex = 0;
|
||||
}
|
||||
|
||||
void CCachedRenderData::SetModel( int model )
|
||||
{
|
||||
Assert(m_Body >= 0);
|
||||
m_Model = model;
|
||||
m_CacheDict[m_Body].EnsureCount(m_Model+1);
|
||||
m_Mesh = -1;
|
||||
m_pFirstFlexIndex = 0;
|
||||
m_pFirstThinFlexIndex = 0;
|
||||
m_pFirstWorldIndex = 0;
|
||||
}
|
||||
|
||||
void CCachedRenderData::SetMesh( int mesh )
|
||||
{
|
||||
Assert((m_Model >= 0) && (m_Body >= 0));
|
||||
|
||||
m_Mesh = mesh;
|
||||
m_CacheDict[m_Body][m_Model].EnsureCount(m_Mesh+1);
|
||||
|
||||
// At this point, we should have all 3 defined.
|
||||
CacheDict_t& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
|
||||
|
||||
if (dict.m_Tag == m_CurrentTag)
|
||||
{
|
||||
m_pFirstFlexIndex = &m_pFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstThinFlexIndex = &m_pThinFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstWorldIndex = &m_pWorldIndex[dict.m_FirstIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFirstFlexIndex = 0;
|
||||
m_pFirstThinFlexIndex = 0;
|
||||
m_pFirstWorldIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to set up a flex computation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool CCachedRenderData::IsFlexComputationDone( ) const
|
||||
{
|
||||
Assert((m_Model >= 0) && (m_Body >= 0) && (m_Mesh >= 0));
|
||||
|
||||
// Lets create the dictionary entry
|
||||
// If the tags match, that means we're doing the computation twice!!!
|
||||
CacheDict_t const& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
|
||||
return (dict.m_FlexTag == m_CurrentTag);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to set up a computation (modifies vertex data)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void CCachedRenderData::SetupComputation( mstudiomesh_t *pMesh, bool flexComputation )
|
||||
{
|
||||
Assert((m_Model >= 0) && (m_Body >= 0) && (m_Mesh >= 0));
|
||||
// Assert( !m_pFirstIndex );
|
||||
|
||||
// Lets create the dictionary entry
|
||||
// If the tags match, that means we're doing the computation twice!!!
|
||||
CacheDict_t& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
|
||||
if (dict.m_Tag != m_CurrentTag)
|
||||
{
|
||||
dict.m_FirstIndex = m_IndexCount;
|
||||
dict.m_IndexCount = pMesh->numvertices;
|
||||
dict.m_Tag = m_CurrentTag;
|
||||
m_IndexCount += dict.m_IndexCount;
|
||||
}
|
||||
|
||||
if (flexComputation)
|
||||
dict.m_FlexTag = m_CurrentTag;
|
||||
|
||||
m_pFirstFlexIndex = &m_pFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstThinFlexIndex = &m_pThinFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstWorldIndex = &m_pWorldIndex[dict.m_FirstIndex];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new flexed vertex to be associated with a vertex
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CachedPosNormTan_t* CCachedRenderData::CreateFlexVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstFlexIndex );
|
||||
Assert( m_pFirstFlexIndex[vertex].m_Tag != m_CurrentTag );
|
||||
|
||||
Assert ( m_FlexVertexCount < MAXSTUDIOFLEXVERTS );
|
||||
if ( m_FlexVertexCount >= MAXSTUDIOFLEXVERTS )
|
||||
return NULL;
|
||||
|
||||
// Point the flex list to the new flexed vertex
|
||||
m_pFirstFlexIndex[vertex].m_Tag = m_CurrentTag;
|
||||
m_pFirstFlexIndex[vertex].m_VertexIndex = m_FlexVertexCount;
|
||||
|
||||
// Add a new flexed vert to the flexed vertex list
|
||||
++m_FlexVertexCount;
|
||||
|
||||
return GetFlexVertex( vertex );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new flexed vertex to be associated with a vertex
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CachedPosNorm_t* CCachedRenderData::CreateThinFlexVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstThinFlexIndex );
|
||||
Assert( m_pFirstThinFlexIndex[vertex].m_Tag != m_CurrentTag );
|
||||
|
||||
Assert ( m_ThinFlexVertexCount < MAXSTUDIOFLEXVERTS );
|
||||
if ( m_ThinFlexVertexCount >= MAXSTUDIOFLEXVERTS )
|
||||
return NULL;
|
||||
|
||||
// Point the flex list to the new flexed vertex
|
||||
m_pFirstThinFlexIndex[vertex].m_Tag = m_CurrentTag;
|
||||
m_pFirstThinFlexIndex[vertex].m_VertexIndex = m_ThinFlexVertexCount;
|
||||
|
||||
// Add a new flexed vert to the thin flexed vertex list
|
||||
++m_ThinFlexVertexCount;
|
||||
|
||||
return GetThinFlexVertex( vertex );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Re-normalize the surface normals and tangents of the flexed vertices
|
||||
// No thin ones since they're intended to be deltas, not unit vectors
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCachedRenderData::RenormalizeFlexVertices( bool bHasTangentData, bool bQuadList )
|
||||
{
|
||||
for ( int i = 0; i < m_FlexVertexCount; i++ )
|
||||
{
|
||||
m_pFlexVerts[i].m_Normal.AsVector3D().NormalizeInPlace();
|
||||
if ( bHasTangentData )
|
||||
{
|
||||
m_pFlexVerts[i].m_TangentS.AsVector3D().NormalizeInPlace();
|
||||
|
||||
if ( bQuadList )
|
||||
{
|
||||
float flClampedWrinkle = MAX( MIN( m_pFlexVerts[i].m_Position.w, 1 ), -1 ); // -1 to 1
|
||||
float fl1to3Wrinkle = flClampedWrinkle + 2; // 1 to 3
|
||||
m_pFlexVerts[i].m_Position.w = m_pFlexVerts[i].m_TangentS.w * fl1to3Wrinkle;// Sign is tangent flip
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new flexed vertex to be associated with a vertex
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
CachedPosNorm_t* CCachedRenderData::CreateWorldVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstWorldIndex );
|
||||
if ( m_pFirstWorldIndex[vertex].m_Tag != m_CurrentTag )
|
||||
{
|
||||
// Point the world list to the new world vertex
|
||||
Assert( m_WorldVertexCount < MAXSTUDIOVERTS );
|
||||
m_pFirstWorldIndex[vertex].m_Tag = m_CurrentTag;
|
||||
m_pFirstWorldIndex[vertex].m_VertexIndex = m_WorldVertexCount;
|
||||
|
||||
// Add a new world vert to the world vertex list
|
||||
++m_WorldVertexCount;
|
||||
}
|
||||
return GetWorldVertex( vertex );
|
||||
}
|
||||
|
||||
330
studiorender/flexrenderdata.h
Normal file
330
studiorender/flexrenderdata.h
Normal file
@@ -0,0 +1,330 @@
|
||||
//========= Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef FLEXRENDERDATA_H
|
||||
#define FLEXRENDERDATA_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "mathlib/vector.h"
|
||||
#include "mathlib/ssemath.h"
|
||||
#include "utlvector.h"
|
||||
#include "studio.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct mstudiomesh_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used by flex vertex data cache
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct CachedPosNormTan_t
|
||||
{
|
||||
Vector4D m_Position;
|
||||
Vector4D m_Normal;
|
||||
Vector4D m_TangentS;
|
||||
|
||||
CachedPosNormTan_t() {}
|
||||
|
||||
CachedPosNormTan_t( CachedPosNormTan_t const& src )
|
||||
{
|
||||
Vector4DCopy( src.m_Position, m_Position );
|
||||
Vector4DCopy( src.m_Normal, m_Normal );
|
||||
Vector4DCopy( src.m_TangentS, m_TangentS );
|
||||
Assert( m_TangentS.w == 1.0f || m_TangentS.w == -1.0f );
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used by world (decal) vertex data cache
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct CachedPosNorm_t
|
||||
{
|
||||
Vector4DAligned m_Position;
|
||||
Vector4DAligned m_Normal;
|
||||
|
||||
CachedPosNorm_t() {}
|
||||
|
||||
CachedPosNorm_t( CachedPosNorm_t const& src )
|
||||
{
|
||||
Vector4DCopy( src.m_Position, m_Position );
|
||||
Vector4DCopy( src.m_Normal, m_Normal );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stores flex vertex data and world (decal) vertex data for the lifetime of the model rendering
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
class CCachedRenderData
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
CCachedRenderData();
|
||||
|
||||
// Call this when we start to render a new model
|
||||
void StartModel();
|
||||
|
||||
// Used to hook ourselves into a particular body part, model, and mesh
|
||||
void SetBodyPart( int bodypart );
|
||||
void SetModel( int model );
|
||||
void SetMesh( int mesh );
|
||||
|
||||
// For faster setup in the decal code
|
||||
void SetBodyModelMesh( int body, int model, int mesh );
|
||||
|
||||
// Used to set up a flex computation
|
||||
bool IsFlexComputationDone( ) const;
|
||||
|
||||
// Used to set up a computation (for world or flex data)
|
||||
void SetupComputation( mstudiomesh_t *pMesh, bool flexComputation = false );
|
||||
|
||||
// Is a particular vertex flexed?
|
||||
bool IsVertexFlexed( int vertex ) const;
|
||||
bool IsThinVertexFlexed( int vertex ) const;
|
||||
|
||||
// Checks to see if the vertex is defined
|
||||
bool IsVertexPositionCached( int vertex ) const;
|
||||
|
||||
// Gets a flexed vertex
|
||||
CachedPosNormTan_t* GetFlexVertex( int vertex );
|
||||
|
||||
// Gets a flexed vertex
|
||||
CachedPosNorm_t* GetThinFlexVertex( int vertex );
|
||||
|
||||
// Creates a new flexed vertex to be associated with a vertex
|
||||
CachedPosNormTan_t* CreateFlexVertex( int vertex );
|
||||
|
||||
// Creates a new flexed vertex to be associated with a vertex
|
||||
CachedPosNorm_t* CreateThinFlexVertex( int vertex );
|
||||
|
||||
// Renormalizes the normals and tangents of the flex verts
|
||||
void RenormalizeFlexVertices( bool bHasTangentData, bool bQuadList );
|
||||
|
||||
// Gets a decal vertex
|
||||
CachedPosNorm_t* GetWorldVertex( int vertex );
|
||||
|
||||
// Creates a new decal vertex to be associated with a vertex
|
||||
CachedPosNorm_t* CreateWorldVertex( int vertex );
|
||||
|
||||
template< class T >
|
||||
void ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, T *pvanim, int vertCount, float w1, float w2, float w3, float w4 );
|
||||
|
||||
void ComputeFlexedVertex_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_t *pvanim, int vertCount, float w1, float w2, float w3, float w4);
|
||||
void ComputeFlexedVertexWrinkle_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_wrinkle_t *pvanim, int vertCount, float w1, float w2, float w3, float w4);
|
||||
private:
|
||||
// Used to create the flex render data. maps
|
||||
struct CacheIndex_t
|
||||
{
|
||||
unsigned short m_Tag;
|
||||
unsigned short m_VertexIndex;
|
||||
};
|
||||
|
||||
// A dictionary for the cached data
|
||||
struct CacheDict_t
|
||||
{
|
||||
unsigned short m_FirstIndex;
|
||||
unsigned short m_IndexCount;
|
||||
unsigned short m_Tag;
|
||||
unsigned short m_FlexTag;
|
||||
|
||||
CacheDict_t() : m_Tag(0), m_FlexTag(0) {}
|
||||
};
|
||||
|
||||
typedef CUtlVector< CacheDict_t > CacheMeshDict_t;
|
||||
typedef CUtlVector< CacheMeshDict_t > CacheModelDict_t;
|
||||
typedef CUtlVector< CacheModelDict_t > CacheBodyPartDict_t;
|
||||
|
||||
// Flex data, allocated for the lifespan of rendering
|
||||
// Can't use UtlVector due to alignment issues
|
||||
int m_FlexVertexCount;
|
||||
CachedPosNormTan_t m_pFlexVerts[MAXSTUDIOFLEXVERTS+1];
|
||||
|
||||
// Flex data, allocated for the lifespan of rendering
|
||||
// Can't use UtlVector due to alignment issues
|
||||
int m_ThinFlexVertexCount;
|
||||
CachedPosNorm_t m_pThinFlexVerts[MAXSTUDIOFLEXVERTS+1];
|
||||
|
||||
// World data, allocated for the lifespan of rendering
|
||||
// Can't use UtlVector due to alignment issues
|
||||
int m_WorldVertexCount;
|
||||
CachedPosNorm_t m_pWorldVerts[MAXSTUDIOVERTS+1];
|
||||
|
||||
// Maps actual mesh vertices into flex cache + world cache indices
|
||||
int m_IndexCount;
|
||||
CacheIndex_t m_pFlexIndex[MAXSTUDIOVERTS+1];
|
||||
CacheIndex_t m_pThinFlexIndex[MAXSTUDIOVERTS+1];
|
||||
CacheIndex_t m_pWorldIndex[MAXSTUDIOVERTS+1];
|
||||
|
||||
CacheBodyPartDict_t m_CacheDict;
|
||||
|
||||
// The flex tag
|
||||
unsigned short m_CurrentTag;
|
||||
|
||||
// the current body, model, and mesh
|
||||
int m_Body;
|
||||
int m_Model;
|
||||
int m_Mesh;
|
||||
|
||||
// mapping for the current mesh to flex data
|
||||
CacheIndex_t* m_pFirstFlexIndex;
|
||||
CacheIndex_t* m_pFirstThinFlexIndex;
|
||||
CacheIndex_t* m_pFirstWorldIndex;
|
||||
|
||||
friend class CStudioRender;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks to see if the vertex is defined
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline bool CCachedRenderData::IsVertexFlexed( int vertex ) const
|
||||
{
|
||||
return (m_pFirstFlexIndex && (m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag));
|
||||
}
|
||||
|
||||
inline bool CCachedRenderData::IsThinVertexFlexed( int vertex ) const
|
||||
{
|
||||
return (m_pFirstThinFlexIndex && (m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets an existing flexed vertex associated with a vertex
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CachedPosNormTan_t* CCachedRenderData::GetFlexVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstFlexIndex );
|
||||
Assert( m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag );
|
||||
return &m_pFlexVerts[ m_pFirstFlexIndex[vertex].m_VertexIndex ];
|
||||
}
|
||||
|
||||
inline CachedPosNorm_t* CCachedRenderData::GetThinFlexVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstThinFlexIndex );
|
||||
Assert( m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag );
|
||||
return &m_pThinFlexVerts[ m_pFirstThinFlexIndex[vertex].m_VertexIndex ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks to see if the vertex is defined
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline bool CCachedRenderData::IsVertexPositionCached( int vertex ) const
|
||||
{
|
||||
return (m_pFirstWorldIndex && (m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gets an existing world vertex associated with a vertex
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline CachedPosNorm_t* CCachedRenderData::GetWorldVertex( int vertex )
|
||||
{
|
||||
Assert( m_pFirstWorldIndex );
|
||||
Assert( m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag );
|
||||
return &m_pWorldVerts[ m_pFirstWorldIndex[vertex].m_VertexIndex ];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// For faster setup in the decal code
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
inline void CCachedRenderData::SetBodyModelMesh( int body, int model, int mesh)
|
||||
{
|
||||
m_Body = body;
|
||||
m_Model = model;
|
||||
m_Mesh = mesh;
|
||||
|
||||
// At this point, we should have all 3 defined.
|
||||
CacheDict_t& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
|
||||
|
||||
if (dict.m_Tag == m_CurrentTag)
|
||||
{
|
||||
m_pFirstFlexIndex = &m_pFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstThinFlexIndex = &m_pThinFlexIndex[dict.m_FirstIndex];
|
||||
m_pFirstWorldIndex = &m_pWorldIndex[dict.m_FirstIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFirstFlexIndex = 0;
|
||||
m_pFirstThinFlexIndex = 0;
|
||||
m_pFirstWorldIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//
|
||||
// ** Only execute this function if device supports stream offset **
|
||||
//
|
||||
// Input : pmesh - pointer to a studio mesh
|
||||
// lod - integer lod (0 is most detailed)
|
||||
// Output : none
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CCachedRenderData::ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex,
|
||||
T *pvanim, int vertCount, float w1, float w2, float w3, float w4 )
|
||||
{
|
||||
float w12 = w1 - w2;
|
||||
float w34 = w3 - w4;
|
||||
float flVertAnimFixedPointScale = pStudioHdr->VertAnimFixedPointScale();
|
||||
|
||||
CachedPosNorm_t *pFlexedVertex = NULL;
|
||||
for (int j = 0; j < pflex->numverts; j++)
|
||||
{
|
||||
int n = pvanim[j].index;
|
||||
|
||||
// only flex the indices that are (still) part of this mesh at this lod
|
||||
if ( n >= vertCount )
|
||||
continue;
|
||||
|
||||
float s = pvanim[j].speed;
|
||||
float b = pvanim[j].side;
|
||||
|
||||
Vector4DAligned vPosition, vNormal;
|
||||
pvanim[j].GetDeltaFixed4DAligned( &vPosition, flVertAnimFixedPointScale );
|
||||
pvanim[j].GetNDeltaFixed4DAligned( &vNormal, flVertAnimFixedPointScale );
|
||||
|
||||
if ( !IsThinVertexFlexed(n) )
|
||||
{
|
||||
// Add a new flexed vert to the flexed vertex list
|
||||
pFlexedVertex = CreateThinFlexVertex(n);
|
||||
|
||||
Assert( pFlexedVertex != NULL);
|
||||
|
||||
pFlexedVertex->m_Position.InitZero();
|
||||
pFlexedVertex->m_Normal.InitZero();
|
||||
}
|
||||
else
|
||||
{
|
||||
pFlexedVertex = GetThinFlexVertex(n);
|
||||
}
|
||||
|
||||
s *= 1.0f / 255.0f;
|
||||
b *= 1.0f / 255.0f;
|
||||
|
||||
float wa = w2 + w12 * s;
|
||||
float wb = w4 + w34 * s;
|
||||
float w = wa + ( wb - wa ) * b;
|
||||
Vector4DWeightMAD( w, vPosition, pFlexedVertex->m_Position, vNormal, pFlexedVertex->m_Normal );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FLEXRENDERDATA_H
|
||||
13
studiorender/ihvtestcopy.pl
Normal file
13
studiorender/ihvtestcopy.pl
Normal file
@@ -0,0 +1,13 @@
|
||||
$infile = shift;
|
||||
$outfile = shift;
|
||||
|
||||
open INFILE, "<$infile";
|
||||
@infile = <INFILE>;
|
||||
close INFILE;
|
||||
|
||||
open OUTFILE, ">$outfile";
|
||||
while( shift @infile )
|
||||
{
|
||||
print OUTFILE $_;
|
||||
}
|
||||
close OUTFILE;
|
||||
353
studiorender/r_studio.cpp
Normal file
353
studiorender/r_studio.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// r_studio.cpp: routines for setting up to draw 3DStudio models
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
|
||||
#include "studio.h"
|
||||
#include "studiorender.h"
|
||||
#include "studiorendercontext.h"
|
||||
#include "optimize.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "tier3/tier3.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Figures out what kind of lighting we're gonna want
|
||||
//-----------------------------------------------------------------------------
|
||||
FORCEINLINE StudioModelLighting_t CStudioRender::R_StudioComputeLighting( IMaterial *pMaterial, int materialFlags, ColorMeshInfo_t *pColorMeshes )
|
||||
{
|
||||
// Here, we only do software lighting when the following conditions are met.
|
||||
// 1) The material is vertex lit and we don't have hardware lighting
|
||||
// 2) We're drawing an eyeball
|
||||
// 3) We're drawing mouth-lit stuff
|
||||
|
||||
// FIXME: When we move software lighting into the material system, only need to
|
||||
// test if it's vertex lit
|
||||
|
||||
Assert( pMaterial );
|
||||
bool doMouthLighting = materialFlags && (m_pStudioHdr->nummouths >= 1);
|
||||
|
||||
if ( IsGameConsole() )
|
||||
{
|
||||
// Console does not do software lighting
|
||||
return doMouthLighting ? LIGHTING_MOUTH : LIGHTING_HARDWARE;
|
||||
}
|
||||
|
||||
bool doSoftwareLighting = doMouthLighting ||
|
||||
(pMaterial && pMaterial->IsVertexLit() && pMaterial->NeedsSoftwareLighting() );
|
||||
|
||||
StudioModelLighting_t lighting = LIGHTING_HARDWARE;
|
||||
if ( doMouthLighting )
|
||||
lighting = LIGHTING_MOUTH;
|
||||
else if ( doSoftwareLighting )
|
||||
lighting = LIGHTING_SOFTWARE;
|
||||
|
||||
return lighting;
|
||||
}
|
||||
|
||||
|
||||
IMaterial* CStudioRender::R_StudioSetupSkinAndLighting( IMatRenderContext *pRenderContext, int index, IMaterial **ppMaterials, int materialFlags,
|
||||
void /*IClientRenderable*/ *pClientRenderable, ColorMeshInfo_t *pColorMeshes, StudioModelLighting_t &lighting )
|
||||
{
|
||||
VPROF( "R_StudioSetupSkin" );
|
||||
IMaterial *pMaterial = NULL;
|
||||
bool bCheckForConVarDrawTranslucentSubModels = false;
|
||||
bool translucent;
|
||||
if( m_pRC->m_Config.bWireframe && !m_pRC->m_pForcedMaterial[ 0 ] )
|
||||
{
|
||||
// Initially, assume no displacement mapping
|
||||
pMaterial = m_pMaterialWireframe[m_pRC->m_Config.bDrawZBufferedWireframe?1:0][0];
|
||||
translucent = false;
|
||||
|
||||
// Look to see if the original material is displacement mapped
|
||||
IMaterial *pOriginalMaterial = ppMaterials[index];
|
||||
static unsigned int originalDisplacementMap = 0;
|
||||
IMaterialVar* pOriginalMaterialVar = pOriginalMaterial->FindVarFast( "$displacementmap", &originalDisplacementMap );
|
||||
|
||||
// If we are displacement mapped
|
||||
if ( pOriginalMaterialVar && pOriginalMaterialVar->IsTexture() )
|
||||
{
|
||||
// Switch to displacement mapped wireframe material
|
||||
pMaterial = m_pMaterialWireframe[m_pRC->m_Config.bDrawZBufferedWireframe?1:0][1];
|
||||
|
||||
static unsigned int newDisplacementMap = 0;
|
||||
IMaterialVar* pNewMaterialVar = pMaterial->FindVarFast( "$displacementmap", &newDisplacementMap );
|
||||
|
||||
if ( pNewMaterialVar )
|
||||
{
|
||||
pNewMaterialVar->SetTextureValue( pOriginalMaterialVar->GetTextureValue() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( m_pRC->m_Config.bShowEnvCubemapOnly )
|
||||
{
|
||||
pMaterial = m_pMaterialModelEnvCubemap;
|
||||
translucent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ( !m_pRC->m_pForcedMaterial[ 0 ] && ( m_pRC->m_nForcedMaterialType != OVERRIDE_DEPTH_WRITE && m_pRC->m_nForcedMaterialType != OVERRIDE_SSAO_DEPTH_WRITE ) )
|
||||
|| m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE )
|
||||
{
|
||||
int nOverrideIndex = GetForcedMaterialOverrideIndex( index );
|
||||
if ( m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE && nOverrideIndex != -1 )
|
||||
{
|
||||
pMaterial = m_pRC->m_pForcedMaterial[ nOverrideIndex ];
|
||||
}
|
||||
else
|
||||
{
|
||||
pMaterial = ppMaterials[index];
|
||||
}
|
||||
if ( !pMaterial )
|
||||
{
|
||||
Assert( 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
|
||||
}
|
||||
else
|
||||
{
|
||||
materialFlags = 0;
|
||||
pMaterial = m_pRC->m_pForcedMaterial[ 0 ];
|
||||
if (m_pRC->m_nForcedMaterialType == OVERRIDE_BUILD_SHADOWS)
|
||||
{
|
||||
// Connect the original material up to the shadow building material
|
||||
// Also bind the original material so its proxies are in the correct state
|
||||
static unsigned int translucentCache = 0;
|
||||
IMaterialVar* pOriginalMaterialVar = pMaterial->FindVarFast( "$translucent_material", &translucentCache );
|
||||
Assert( pOriginalMaterialVar );
|
||||
IMaterial *pOriginalMaterial = ppMaterials[index];
|
||||
if ( pOriginalMaterial )
|
||||
{
|
||||
pRenderContext->Bind( pOriginalMaterial, pClientRenderable );
|
||||
if ( pOriginalMaterial->IsTranslucentUnderModulation() || pOriginalMaterial->IsAlphaTested() )
|
||||
{
|
||||
pOriginalMaterialVar->SetMaterialValue( pOriginalMaterial );
|
||||
}
|
||||
else
|
||||
{
|
||||
pOriginalMaterialVar->SetMaterialValue( NULL );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pOriginalMaterialVar->SetMaterialValue( NULL );
|
||||
}
|
||||
translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
|
||||
}
|
||||
else if ( m_pRC->m_nForcedMaterialType == OVERRIDE_DEPTH_WRITE || m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE )
|
||||
{
|
||||
// Bail if the material is still considered translucent after setting the AlphaModulate to 1.0
|
||||
if ( ppMaterials[index]->IsTranslucentUnderModulation() )
|
||||
return NULL;
|
||||
|
||||
bool bIsAlphaTested = false;
|
||||
bool bUsesTreeSway = false;
|
||||
GetDepthWriteMaterial( &pMaterial, &bIsAlphaTested, &bUsesTreeSway, ppMaterials[ index ], false, ( m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE) );
|
||||
if ( bIsAlphaTested )
|
||||
{
|
||||
SetupAlphaTestedDepthWrite( pMaterial, ppMaterials[index] );
|
||||
}
|
||||
if ( bUsesTreeSway )
|
||||
{
|
||||
SetupTreeSwayDepthWrite( pMaterial, ppMaterials[index] );
|
||||
}
|
||||
|
||||
translucent = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
|
||||
}
|
||||
}
|
||||
|
||||
// Set this bool to check after the bind below
|
||||
bCheckForConVarDrawTranslucentSubModels = true;
|
||||
}
|
||||
|
||||
lighting = R_StudioComputeLighting( pMaterial, materialFlags, pColorMeshes );
|
||||
if ( lighting == LIGHTING_MOUTH )
|
||||
{
|
||||
if ( !m_pRC->m_Config.bTeeth || !R_TeethAreVisible() )
|
||||
return NULL;
|
||||
// skin it and light it, but only if we need to.
|
||||
if ( m_pRC->m_Config.m_bSupportsVertexAndPixelShaders )
|
||||
{
|
||||
R_MouthSetupVertexShader( pMaterial );
|
||||
}
|
||||
}
|
||||
|
||||
pRenderContext->Bind( pMaterial, pClientRenderable );
|
||||
|
||||
if ( bCheckForConVarDrawTranslucentSubModels )
|
||||
{
|
||||
if (( m_bDrawTranslucentSubModels && !translucent ) ||
|
||||
( !m_bDrawTranslucentSubModels && translucent ))
|
||||
{
|
||||
m_bSkippedMeshes = true;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pMaterial;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
R_StudioSetupModel
|
||||
based on the body part, figure out which mesh it should be using.
|
||||
inputs:
|
||||
outputs:
|
||||
pstudiomesh
|
||||
pmdl
|
||||
=================
|
||||
*/
|
||||
int R_StudioSetupModel( int bodypart, int entity_body, mstudiomodel_t **ppSubModel,
|
||||
const studiohdr_t *pStudioHdr )
|
||||
{
|
||||
int index;
|
||||
mstudiobodyparts_t *pbodypart;
|
||||
|
||||
if (bodypart > pStudioHdr->numbodyparts)
|
||||
{
|
||||
ConDMsg ("R_StudioSetupModel: no such bodypart %d\n", bodypart);
|
||||
bodypart = 0;
|
||||
}
|
||||
|
||||
pbodypart = pStudioHdr->pBodypart( bodypart );
|
||||
|
||||
index = entity_body / pbodypart->base;
|
||||
index = index % pbodypart->nummodels;
|
||||
|
||||
Assert( ppSubModel );
|
||||
*ppSubModel = pbodypart->pModel( index );
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generates the PoseToBone Matrix nessecary to align the given bone with the
|
||||
// world.
|
||||
//-----------------------------------------------------------------------------
|
||||
static void ScreenAlignBone( matrix3x4_t *pPoseToWorld, mstudiobone_t *pCurBone,
|
||||
const Vector& vecViewOrigin, const matrix3x4_t &boneToWorld )
|
||||
{
|
||||
// Grab the world translation:
|
||||
Vector vT( boneToWorld[0][3], boneToWorld[1][3], boneToWorld[2][3] );
|
||||
|
||||
// Construct the coordinate frame:
|
||||
// Initialized to get rid of compiler
|
||||
Vector vX, vY, vZ;
|
||||
|
||||
if( pCurBone->flags & BONE_SCREEN_ALIGN_SPHERE )
|
||||
{
|
||||
vX = vecViewOrigin - vT;
|
||||
VectorNormalize(vX);
|
||||
vZ = Vector(0,0,1);
|
||||
vY = vZ.Cross(vX);
|
||||
VectorNormalize(vY);
|
||||
vZ = vX.Cross(vY);
|
||||
VectorNormalize(vZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( pCurBone->flags & BONE_SCREEN_ALIGN_CYLINDER );
|
||||
vX.Init( boneToWorld[0][0], boneToWorld[1][0], boneToWorld[2][0] );
|
||||
vZ = vecViewOrigin - vT;
|
||||
VectorNormalize(vZ);
|
||||
vY = vZ.Cross(vX);
|
||||
VectorNormalize(vY);
|
||||
vZ = vX.Cross(vY);
|
||||
VectorNormalize(vZ);
|
||||
}
|
||||
|
||||
matrix3x4_t matBoneBillboard(
|
||||
vX.x, vY.x, vZ.x, vT.x,
|
||||
vX.y, vY.y, vZ.y, vT.y,
|
||||
vX.z, vY.z, vZ.z, vT.z );
|
||||
ConcatTransforms( matBoneBillboard, pCurBone->poseToBone, *pPoseToWorld );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes PoseToWorld from BoneToWorld
|
||||
//-----------------------------------------------------------------------------
|
||||
void ComputePoseToWorld( matrix3x4_t *pPoseToWorld, studiohdr_t *pStudioHdr, int boneMask, const Vector& vecViewOrigin, const matrix3x4_t *pBoneToWorld )
|
||||
{
|
||||
if ( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP )
|
||||
{
|
||||
// by definition, these always have an identity poseToBone transform
|
||||
MatrixCopy( pBoneToWorld[ 0 ], pPoseToWorld[ 0 ] );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !pStudioHdr->pLinearBones() )
|
||||
{
|
||||
// convert bone to world transformations into pose to world transformations
|
||||
for (int i = 0; i < pStudioHdr->numbones; i++)
|
||||
{
|
||||
const mstudiobone_t *pCurBone = pStudioHdr->pBone( i );
|
||||
if ( !(pCurBone->flags & boneMask) )
|
||||
continue;
|
||||
|
||||
ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones();
|
||||
|
||||
// convert bone to world transformations into pose to world transformations
|
||||
for (int i = 0; i < pStudioHdr->numbones; i++)
|
||||
{
|
||||
if ( !(pLinearBones->flags(i) & boneMask) )
|
||||
continue;
|
||||
|
||||
ConcatTransforms( pBoneToWorld[ i ], pLinearBones->poseToBone(i), pPoseToWorld[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// These don't seem to be used in any existing QC file, re-enable in a future project?
|
||||
// Pretransform
|
||||
if( !( pCurBone->flags & ( BONE_SCREEN_ALIGN_SPHERE | BONE_SCREEN_ALIGN_CYLINDER )))
|
||||
{
|
||||
ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this bone is screen aligned, then generate a PoseToWorld matrix that billboards the bone
|
||||
ScreenAlignBone( &pPoseToWorld[i], pCurBone, vecViewOrigin, pBoneToWorld[i] );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper to determine which material type to use depending on what strip
|
||||
// header flags are set.
|
||||
//-----------------------------------------------------------------------------
|
||||
MaterialPrimitiveType_t GetPrimitiveTypeForStripHeaderFlags( unsigned char Flags )
|
||||
{
|
||||
if ( Flags & OptimizedModel::STRIP_IS_QUADLIST_EXTRA )
|
||||
return MATERIAL_SUBD_QUADS_EXTRA;
|
||||
else if( Flags & OptimizedModel::STRIP_IS_QUADLIST_REG )
|
||||
return MATERIAL_SUBD_QUADS_REG;
|
||||
return MATERIAL_TRIANGLES;
|
||||
}
|
||||
2460
studiorender/r_studiodecal.cpp
Normal file
2460
studiorender/r_studiodecal.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2968
studiorender/r_studiodraw.cpp
Normal file
2968
studiorender/r_studiodraw.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1609
studiorender/r_studiodraw_computeflexedvertex.cpp
Normal file
1609
studiorender/r_studiodraw_computeflexedvertex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
935
studiorender/r_studioflex.cpp
Normal file
935
studiorender/r_studioflex.cpp
Normal file
@@ -0,0 +1,935 @@
|
||||
//===== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "studio.h"
|
||||
#include "studiorendercontext.h"
|
||||
#include "bitmap/imageformat.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "studiorender.h"
|
||||
#include "pixelwriter.h"
|
||||
#include "vtf/vtf.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define sign( a ) (((a) < 0) ? -1 : (((a) > 0) ? 1 : 0 ))
|
||||
|
||||
void CStudioRender::R_StudioEyeballPosition( const mstudioeyeball_t *peyeball, eyeballstate_t *pstate )
|
||||
{
|
||||
// Vector forward;
|
||||
// Vector org, right, up;
|
||||
|
||||
pstate->peyeball = peyeball;
|
||||
|
||||
Vector tmp;
|
||||
// move eyeball into worldspace
|
||||
{
|
||||
// ConDMsg("%.2f %.2f %.2f\n", peyeball->org[0], peyeball->org[1], peyeball->org[2] );
|
||||
|
||||
VectorCopy( peyeball->org, tmp );
|
||||
|
||||
tmp[0] += m_pRC->m_Config.fEyeShiftX * sign( tmp[0] );
|
||||
tmp[1] += m_pRC->m_Config.fEyeShiftY * sign( tmp[1] );
|
||||
tmp[2] += m_pRC->m_Config.fEyeShiftZ * sign( tmp[2] );
|
||||
}
|
||||
VectorTransform( tmp, m_pBoneToWorld[peyeball->bone], pstate->org );
|
||||
VectorRotate( peyeball->up, m_pBoneToWorld[peyeball->bone], pstate->up );
|
||||
|
||||
// look directly at target
|
||||
VectorSubtract( m_pRC->m_ViewTarget, pstate->org, pstate->forward );
|
||||
VectorNormalize( pstate->forward );
|
||||
|
||||
if ( !m_pRC->m_Config.bEyeMove )
|
||||
{
|
||||
VectorRotate( peyeball->forward, m_pBoneToWorld[peyeball->bone], pstate->forward );
|
||||
VectorScale( pstate->forward, -1 ,pstate->forward ); // ???
|
||||
}
|
||||
|
||||
CrossProduct( pstate->forward, pstate->up, pstate->right );
|
||||
VectorNormalize( pstate->right );
|
||||
|
||||
// shift N degrees off of the target
|
||||
float dz;
|
||||
dz = peyeball->zoffset;
|
||||
|
||||
VectorMA( pstate->forward, peyeball->zoffset + dz, pstate->right, pstate->forward );
|
||||
|
||||
#if 0
|
||||
// add random jitter
|
||||
VectorMA( forward, RandomFloat( -0.02, 0.02 ), right, forward );
|
||||
VectorMA( forward, RandomFloat( -0.02, 0.02 ), up, forward );
|
||||
#endif
|
||||
|
||||
VectorNormalize( pstate->forward );
|
||||
// re-aim eyes
|
||||
CrossProduct( pstate->forward, pstate->up, pstate->right );
|
||||
VectorNormalize( pstate->right );
|
||||
|
||||
CrossProduct( pstate->right, pstate->forward, pstate->up );
|
||||
VectorNormalize( pstate->up );
|
||||
|
||||
float scale = (1.0 / peyeball->iris_scale) + m_pRC->m_Config.fEyeSize;
|
||||
|
||||
if (scale > 0)
|
||||
scale = 1.0 / scale;
|
||||
|
||||
VectorScale( &pstate->right[0], -scale, pstate->mat[0] );
|
||||
VectorScale( &pstate->up[0], -scale, pstate->mat[1] );
|
||||
|
||||
pstate->mat[0][3] = -DotProduct( &pstate->org[0], pstate->mat[0] ) + 0.5f;
|
||||
pstate->mat[1][3] = -DotProduct( &pstate->org[0], pstate->mat[1] ) + 0.5f;
|
||||
|
||||
// FIXME: push out vertices for cornea
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CStudioRender::R_StudioEyelidFACS( const mstudioeyeball_t *peyeball, const eyeballstate_t *pstate )
|
||||
{
|
||||
if ( peyeball->m_bNonFACS )
|
||||
return;
|
||||
|
||||
Vector pos, headup, headforward;
|
||||
|
||||
float upperlid = DEG2RAD( 9.5 );
|
||||
float lowerlid = DEG2RAD( -26.4 );
|
||||
|
||||
// FIXME: Crash workaround
|
||||
Vector vecNormTarget;
|
||||
vecNormTarget.Init( peyeball->uppertarget[0], peyeball->uppertarget[1], peyeball->uppertarget[2] );
|
||||
vecNormTarget /= peyeball->radius;
|
||||
vecNormTarget.x = clamp( vecNormTarget.x, -1.0f, 1.0f );
|
||||
vecNormTarget.y = clamp( vecNormTarget.y, -1.0f, 1.0f );
|
||||
vecNormTarget.z = clamp( vecNormTarget.z, -1.0f, 1.0f );
|
||||
|
||||
// get weighted position of eyeball angles based on the "raiser", "neutral", and "lowerer" controls
|
||||
upperlid = m_pFlexWeights[peyeball->upperflexdesc[0]] * asin( vecNormTarget.x );
|
||||
upperlid += m_pFlexWeights[peyeball->upperflexdesc[1]] * asin( vecNormTarget.y );
|
||||
upperlid += m_pFlexWeights[peyeball->upperflexdesc[2]] * asin( vecNormTarget.z );
|
||||
|
||||
vecNormTarget.Init( peyeball->lowertarget[0], peyeball->lowertarget[1], peyeball->lowertarget[2] );
|
||||
vecNormTarget /= peyeball->radius;
|
||||
vecNormTarget.x = clamp( vecNormTarget.x, -1.0f, 1.0f );
|
||||
vecNormTarget.y = clamp( vecNormTarget.y, -1.0f, 1.0f );
|
||||
vecNormTarget.z = clamp( vecNormTarget.z, -1.0f, 1.0f );
|
||||
|
||||
lowerlid = m_pFlexWeights[peyeball->lowerflexdesc[0]] * asin( vecNormTarget.x );
|
||||
lowerlid += m_pFlexWeights[peyeball->lowerflexdesc[1]] * asin( vecNormTarget.y );
|
||||
lowerlid += m_pFlexWeights[peyeball->lowerflexdesc[2]] * asin( vecNormTarget.z );
|
||||
|
||||
// ConDMsg("%.1f %.1f\n", RAD2DEG( upperlid ), RAD2DEG( lowerlid ) );
|
||||
|
||||
float sinupper, cosupper, sinlower, coslower;
|
||||
SinCos( upperlid, &sinupper, &cosupper );
|
||||
SinCos( lowerlid, &sinlower, &coslower );
|
||||
|
||||
// convert to head relative space
|
||||
VectorIRotate( pstate->up, m_pBoneToWorld[peyeball->bone], headup );
|
||||
VectorIRotate( pstate->forward, m_pBoneToWorld[peyeball->bone], headforward );
|
||||
|
||||
// upper lid
|
||||
VectorScale( headup, sinupper * peyeball->radius, pos );
|
||||
VectorMA( pos, cosupper * peyeball->radius, headforward, pos );
|
||||
m_pFlexWeights[peyeball->upperlidflexdesc] = DotProduct( pos, peyeball->up );
|
||||
|
||||
// lower lid
|
||||
VectorScale( headup, sinlower * peyeball->radius, pos );
|
||||
VectorMA( pos, coslower * peyeball->radius, headforward, pos );
|
||||
m_pFlexWeights[peyeball->lowerlidflexdesc] = DotProduct( pos, peyeball->up );
|
||||
// ConDMsg("%.4f %.4f\n", m_pRC->m_FlexWeights[peyeball->upperlidflex], m_pRC->m_FlexWeights[peyeball->lowerlidflex] );
|
||||
}
|
||||
|
||||
|
||||
void CStudioRender::MaterialPlanerProjection( const matrix3x4_t& mat, int count, const Vector *psrcverts, Vector2D *pdesttexcoords )
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
pdesttexcoords[i][0] = DotProduct( &psrcverts[i].x, mat[0] ) + mat[0][3];
|
||||
pdesttexcoords[i][1] = DotProduct( &psrcverts[i].x, mat[1] ) + mat[1][3];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Ramp and clamp the flex weight
|
||||
//-----------------------------------------------------------------------------
|
||||
float CStudioRender::RampFlexWeight( mstudioflex_t &flex, float w )
|
||||
{
|
||||
if ( w <= flex.target0 || w >= flex.target3 )
|
||||
{
|
||||
w = 0.0; // value outside of range
|
||||
}
|
||||
else if ( w < flex.target1 )
|
||||
{
|
||||
w = (w - flex.target0) / (flex.target1 - flex.target0); // 0 to 1 ramp
|
||||
}
|
||||
else if ( w > flex.target2 )
|
||||
{
|
||||
w = (flex.target3 - w) / (flex.target3 - flex.target2); // 1 to 0 ramp
|
||||
}
|
||||
else
|
||||
{
|
||||
w = 1.0; // plat
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Setup the flex verts for this rendering
|
||||
//-----------------------------------------------------------------------------
|
||||
void CStudioRender::R_StudioFlexVerts( mstudiomesh_t *pmesh, int lod, bool bQuadList )
|
||||
{
|
||||
VPROF_BUDGET( "CStudioRender::R_StudioFlexVerts", VPROF_BUDGETGROUP_MODEL_RENDERING );
|
||||
|
||||
Assert( pmesh );
|
||||
|
||||
const float flVertAnimFixedPointScale = m_pStudioHdr->VertAnimFixedPointScale();
|
||||
|
||||
// There's a chance we can actually do the flex twice on a single mesh
|
||||
// since there's flexed HW + SW portions of the mesh.
|
||||
if ( m_VertexCache.IsFlexComputationDone() )
|
||||
return;
|
||||
|
||||
// Get pointers to geometry
|
||||
if ( !pmesh->pModel()->CacheVertexData( m_pStudioHdr ) )
|
||||
{
|
||||
// not available yet
|
||||
return;
|
||||
}
|
||||
const mstudio_meshvertexdata_t *vertData = pmesh->GetVertexData( m_pStudioHdr );
|
||||
Assert( vertData );
|
||||
if ( !vertData )
|
||||
{
|
||||
static unsigned int warnCount = 0;
|
||||
if ( warnCount++ < 20 )
|
||||
Warning( "ERROR: model verts have been compressed, cannot render! (use \"-no_compressed_vvds\")" );
|
||||
return;
|
||||
}
|
||||
|
||||
// The flex data should have been converted to the new (fixed-point) format on load:
|
||||
Assert( m_pStudioHdr->flags & STUDIOHDR_FLAGS_FLEXES_CONVERTED );
|
||||
if ( ( m_pStudioHdr->flags & STUDIOHDR_FLAGS_FLEXES_CONVERTED ) == 0 )
|
||||
{
|
||||
static unsigned int flexConversionTimesWarned = 0;
|
||||
if ( flexConversionTimesWarned++ < 6 )
|
||||
Warning( "ERROR: flex verts have not been converted (queued loader refcount bug?) - expect to see 'exploded' faces" );
|
||||
}
|
||||
|
||||
mstudiovertex_t *pVertices = vertData->Vertex( 0 );
|
||||
Vector4D *pStudioTangentS = vertData->HasTangentData() ? vertData->TangentS( 0 ) : NULL;
|
||||
mstudioflex_t *pflex = pmesh->pFlex( 0 );
|
||||
|
||||
m_VertexCache.SetupComputation( pmesh, true );
|
||||
|
||||
// Apply flex weights
|
||||
int i, j, n;
|
||||
|
||||
for ( i = 0; i < pmesh->numflexes; i++ )
|
||||
{
|
||||
float w1 = RampFlexWeight( pflex[i], m_pFlexWeights[ pflex[i].flexdesc ] );
|
||||
float w2 = RampFlexWeight( pflex[i], m_pFlexDelayedWeights[ pflex[i].flexdesc ] );
|
||||
|
||||
float w3, w4;
|
||||
if ( pflex[i].flexpair != 0)
|
||||
{
|
||||
w3 = RampFlexWeight( pflex[i], m_pFlexWeights[ pflex[i].flexpair ] );
|
||||
w4 = RampFlexWeight( pflex[i], m_pFlexDelayedWeights[ pflex[i].flexpair ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
w3 = w1;
|
||||
w4 = w2;
|
||||
}
|
||||
|
||||
if ( w1 > -0.001 && w1 < 0.001 && w2 > -0.001 && w2 < 0.001 )
|
||||
{
|
||||
if ( w3 > -0.001 && w3 < 0.001 && w4 > -0.001 && w4 < 0.001 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
byte *pvanim = pflex[i].pBaseVertanim();
|
||||
int nVAnimSizeBytes = pflex[i].VertAnimSizeBytes();
|
||||
|
||||
bool bWrinkleFlex = pflex[i].vertanimtype == STUDIO_VERT_ANIM_WRINKLE;
|
||||
|
||||
for ( j = 0; j < pflex[i].numverts; j++ )
|
||||
{
|
||||
mstudiovertanim_t *pAnim = (mstudiovertanim_t*)( pvanim + j * nVAnimSizeBytes );
|
||||
n = pAnim->index;
|
||||
|
||||
// Only flex the indices that are (still) part of this mesh need lod restriction here
|
||||
if ( n < pmesh->vertexdata.numLODVertexes[lod] )
|
||||
{
|
||||
mstudiovertex_t &vert = pVertices[n];
|
||||
|
||||
CachedPosNormTan_t* pFlexedVertex;
|
||||
if ( !m_VertexCache.IsVertexFlexed(n) )
|
||||
{
|
||||
pFlexedVertex = m_VertexCache.CreateFlexVertex(n); // Add a new flexed vert to the list
|
||||
|
||||
if ( pFlexedVertex == NULL ) // Skip processing if no more can be allocated
|
||||
continue;
|
||||
|
||||
VectorCopy( vert.m_vecPosition, pFlexedVertex->m_Position.AsVector3D() );
|
||||
pFlexedVertex->m_Position.w = 0.0f;
|
||||
|
||||
VectorCopy( vert.m_vecNormal, pFlexedVertex->m_Normal.AsVector3D() );
|
||||
|
||||
if ( pStudioTangentS )
|
||||
{
|
||||
Vector4DCopy( pStudioTangentS[n], pFlexedVertex->m_TangentS );
|
||||
Assert( pFlexedVertex->m_TangentS.w == -1.0f || pFlexedVertex->m_TangentS.w == 1.0f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pFlexedVertex = m_VertexCache.GetFlexVertex(n);
|
||||
}
|
||||
|
||||
float s = pAnim->speed * ( 1.0f/255.0f );
|
||||
float b = pAnim->side * ( 1.0f/255.0f );
|
||||
|
||||
float w = (w1 * s + (1.0f - s) * w2) * (1.0f - b) + b * (w3 * s + (1.0f - s) * w4);
|
||||
|
||||
// Accumulate weighted deltas
|
||||
pFlexedVertex->m_Position.AsVector3D() += pAnim->GetDeltaFixed( flVertAnimFixedPointScale ) * w;
|
||||
|
||||
if ( bWrinkleFlex )
|
||||
{
|
||||
float delta = ((mstudiovertanim_wrinkle_t *)pAnim)->GetWrinkleDeltaFixed( flVertAnimFixedPointScale );
|
||||
pFlexedVertex->m_Position.w += w * delta;
|
||||
}
|
||||
|
||||
if ( !bQuadList )
|
||||
{
|
||||
pFlexedVertex->m_Normal.AsVector3D() += pAnim->GetNDeltaFixed( flVertAnimFixedPointScale ) * w;
|
||||
}
|
||||
|
||||
if ( pStudioTangentS )
|
||||
{
|
||||
pFlexedVertex->m_TangentS.AsVector3D() += pAnim->GetNDeltaFixed( flVertAnimFixedPointScale ) * w;
|
||||
Assert( pFlexedVertex->m_TangentS.w == -1.0f || pFlexedVertex->m_TangentS.w == 1.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_VertexCache.RenormalizeFlexVertices( vertData->HasTangentData(), bQuadList );
|
||||
}
|
||||
|
||||
// REMOVED!! Look in version 32 if you need it.
|
||||
//static void R_StudioEyeballNormals( const mstudioeyeball_t *peyeball, int count, const Vector *psrcverts, Vector *pdestnorms )
|
||||
|
||||
#define KERNEL_DIAMETER 2
|
||||
#define KERNEL_TEXELS (KERNEL_DIAMETER)
|
||||
#define KERNEL_TEXEL_RADIUS (KERNEL_TEXELS / 2)
|
||||
|
||||
inline float GlintGaussSpotCoefficient( float dx, float dy /*, float *table */ )
|
||||
{
|
||||
const float radius = KERNEL_DIAMETER / 2;
|
||||
const float rsq = 1.0f / (radius * radius);
|
||||
float r2 = (dx * dx + dy * dy) * rsq;
|
||||
if (r2 <= 1.0f)
|
||||
{
|
||||
return exp( -25.0 * r2 );
|
||||
// NOTE: This optimization doesn't make much of a difference
|
||||
//int index = r2 * (GLINT_TABLE_ENTRIES-1);
|
||||
//return table[index];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CStudioRender::AddGlint( CPixelWriter &pixelWriter, float x, float y, const Vector& color )
|
||||
{
|
||||
x = (x + 0.5f) * m_GlintWidth;
|
||||
y = (y + 0.5f) * m_GlintHeight;
|
||||
const float texelRadius = KERNEL_DIAMETER / 2;
|
||||
|
||||
int x0 = (int)x;
|
||||
int y0 = (int)y;
|
||||
int x1 = x0 + texelRadius;
|
||||
int y1 = y0 + texelRadius;
|
||||
x0 -= texelRadius;
|
||||
y0 -= texelRadius;
|
||||
|
||||
// clip light to texture
|
||||
if ( (x0 >= m_GlintWidth) || (x1 < 0) || (y0 >= m_GlintHeight) || (y1 < 0) )
|
||||
return;
|
||||
|
||||
// clamp coordinates
|
||||
if ( x0 < 0 )
|
||||
{
|
||||
x0 = 0;
|
||||
}
|
||||
if ( y0 < 0 )
|
||||
{
|
||||
y0 = 0;
|
||||
}
|
||||
if ( x1 >= m_GlintWidth )
|
||||
{
|
||||
x1 = m_GlintWidth-1;
|
||||
}
|
||||
if ( y1 >= m_GlintHeight )
|
||||
{
|
||||
y1 = m_GlintHeight-1;
|
||||
}
|
||||
|
||||
for (int v = y0; v <= y1; ++v )
|
||||
{
|
||||
pixelWriter.Seek( x0, v );
|
||||
|
||||
for (int u = x0; u <= x1; ++u )
|
||||
{
|
||||
float fu = ((float)u) - x;
|
||||
float fv = ((float)v) - y;
|
||||
const float offset = 0.25;
|
||||
float intensity = GlintGaussSpotCoefficient( fu-offset, fv-offset ) +
|
||||
GlintGaussSpotCoefficient( fu+offset, fv-offset ) +
|
||||
5 * GlintGaussSpotCoefficient( fu, fv ) +
|
||||
GlintGaussSpotCoefficient( fu-offset, fv+offset ) +
|
||||
GlintGaussSpotCoefficient( fu+offset, fv+offset );
|
||||
|
||||
// NOTE: Old filter code multiplies the signal by 8X, so we will too
|
||||
intensity *= (4.0f/9.0f);
|
||||
|
||||
// NOTE: It's much faster to do the work in the dest texture than to touch the memory more
|
||||
// or make more buffers
|
||||
Vector outColor = intensity * color;
|
||||
int r, g, b, a;
|
||||
pixelWriter.ReadPixelNoAdvance( r, g, b, a );
|
||||
outColor.x += TextureToLinear(r);
|
||||
outColor.y += TextureToLinear(g);
|
||||
outColor.z += TextureToLinear(b);
|
||||
pixelWriter.WritePixel( LinearToTexture(outColor.x), LinearToTexture(outColor.y), LinearToTexture(outColor.z) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// glint
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// test/stub code
|
||||
#if 0
|
||||
class CEmptyTextureRegen : public ITextureRegenerator
|
||||
{
|
||||
public:
|
||||
virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
|
||||
{
|
||||
// get the texture
|
||||
unsigned char *pTextureData = pVTFTexture->ImageData( 0, 0, 0 );
|
||||
int nImageSize = pVTFTexture->ComputeMipSize( 0 );
|
||||
memset( pTextureData, 0, nImageSize );
|
||||
}
|
||||
|
||||
// We've got a global instance, no need to delete it
|
||||
virtual void Release() {}
|
||||
};
|
||||
static CEmptyTextureRegen s_GlintTextureRegen;
|
||||
#endif
|
||||
|
||||
class CGlintTextureRegenerator : public ITextureRegenerator
|
||||
{
|
||||
public:
|
||||
virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
|
||||
{
|
||||
// We don't need to reconstitute the bits after a task switch
|
||||
// since we reconstitute them every frame they are used anyways
|
||||
if ( !m_pStudioRender )
|
||||
return;
|
||||
|
||||
if ( ( m_pStudioRender->m_GlintWidth != pVTFTexture->Width() ) ||
|
||||
( m_pStudioRender->m_GlintHeight != pVTFTexture->Height() ) )
|
||||
{
|
||||
m_pStudioRender->m_GlintWidth = pVTFTexture->Width();
|
||||
m_pStudioRender->m_GlintHeight = pVTFTexture->Height();
|
||||
}
|
||||
|
||||
CStudioRender::GlintRenderData_t pRenderData[16];
|
||||
int nGlintCount = m_pStudioRender->BuildGlintRenderData( pRenderData,
|
||||
ARRAYSIZE(pRenderData), m_pState, *m_pVRight, *m_pVUp, *m_pROrigin );
|
||||
|
||||
// setup glint texture
|
||||
unsigned char *pTextureData = pVTFTexture->ImageData( 0, 0, 0 );
|
||||
CPixelWriter pixelWriter;
|
||||
pixelWriter.SetPixelMemory( pVTFTexture->Format(), pTextureData, pVTFTexture->RowSizeInBytes( 0 ) );
|
||||
int nImageSize = pVTFTexture->ComputeMipSize( 0 );
|
||||
memset( pTextureData, 0, nImageSize );
|
||||
|
||||
// Put in glints due to the lights in the scene
|
||||
for ( int i = 0; i < nGlintCount; ++i )
|
||||
{
|
||||
// NOTE: AddGlint is a more expensive solution but it looks better close-up
|
||||
m_pStudioRender->AddGlint( pixelWriter, pRenderData[i].m_vecPosition[0],
|
||||
pRenderData[i].m_vecPosition[1], pRenderData[i].m_vecIntensity );
|
||||
}
|
||||
}
|
||||
|
||||
// We've got a global instance, no need to delete it
|
||||
virtual void Release() {}
|
||||
|
||||
const eyeballstate_t *m_pState;
|
||||
const Vector *m_pVRight;
|
||||
const Vector *m_pVUp;
|
||||
const Vector *m_pROrigin;
|
||||
CStudioRender *m_pStudioRender;
|
||||
};
|
||||
|
||||
static CGlintTextureRegenerator s_GlintTextureRegen;
|
||||
|
||||
static ITexture *s_pProcGlint = NULL;
|
||||
void CStudioRender::PrecacheGlint()
|
||||
{
|
||||
if ( ! m_pGlintTexture )
|
||||
{
|
||||
// Begin block in which all render targets should be allocated
|
||||
|
||||
// Get the texture that we are going to be updating procedurally.
|
||||
m_pGlintTexture = materials->FindTexture( "_rt_eyeglint", TEXTURE_GROUP_RENDER_TARGET );
|
||||
if ( IsErrorTexture( m_pGlintTexture ) )
|
||||
{
|
||||
g_pMaterialSystem->BeginRenderTargetAllocation();
|
||||
m_pGlintTexture = g_pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_eyeglint", 32, 32, RT_SIZE_NO_CHANGE, IMAGE_FORMAT_BGRA8888, MATERIAL_RT_DEPTH_NONE );
|
||||
g_pMaterialSystem->EndRenderTargetAllocation();
|
||||
}
|
||||
m_pGlintTexture->IncrementReferenceCount();
|
||||
|
||||
if ( !IsX360() )
|
||||
{
|
||||
// Get the texture that we are going to be updating procedurally.
|
||||
s_pProcGlint = g_pMaterialSystem->CreateProceduralTexture(
|
||||
"proc_eyeglint", TEXTURE_GROUP_MODEL, 32, 32, IMAGE_FORMAT_BGRA8888, TEXTUREFLAGS_NOMIP|TEXTUREFLAGS_NOLOD );
|
||||
s_pProcGlint->SetTextureRegenerator( &s_GlintTextureRegen );
|
||||
}
|
||||
|
||||
// JAY: I don't see this pattern in the code often. It looks like the material system
|
||||
// would rather than I deal exclusively with IMaterials instead.
|
||||
// So maybe we should bake the LOD texture into the eyes shader.
|
||||
// For now, just hardcode one
|
||||
// UNDONE: Add a $lodtexture to the eyes shader. Maybe add a $lodsize too.
|
||||
// UNDONE: Make eyes texture load $lodtexture and switch to that here instead of black
|
||||
m_pGlintLODTexture = g_pMaterialSystem->FindTexture( IsX360() ? "black" : "vgui/black", NULL, false );
|
||||
m_pGlintLODTexture->IncrementReferenceCount();
|
||||
}
|
||||
}
|
||||
|
||||
void CStudioRender::UncacheGlint()
|
||||
{
|
||||
if ( m_pGlintTexture )
|
||||
{
|
||||
if ( s_pProcGlint )
|
||||
{
|
||||
s_pProcGlint->SetTextureRegenerator( NULL );
|
||||
s_pProcGlint->DecrementReferenceCount();
|
||||
s_pProcGlint = NULL;
|
||||
}
|
||||
m_pGlintTexture->DecrementReferenceCount();
|
||||
m_pGlintTexture = NULL;
|
||||
m_pGlintLODTexture->DecrementReferenceCount();
|
||||
m_pGlintLODTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CStudioRender::BuildGlintRenderData( GlintRenderData_t *pData, int nMaxGlints,
|
||||
const eyeballstate_t *pState, const Vector& vright, const Vector& vup, const Vector& r_origin )
|
||||
{
|
||||
// NOTE: See version 25 for lots of #if 0ed out stuff I removed
|
||||
Vector viewdelta;
|
||||
VectorSubtract( r_origin, pState->org, viewdelta );
|
||||
VectorNormalize( viewdelta );
|
||||
|
||||
// hack cornea position
|
||||
float iris_radius = pState->peyeball->radius * (6.0 / 12.0);
|
||||
float cornea_radius = pState->peyeball->radius * (8.0 / 12.0);
|
||||
|
||||
Vector cornea;
|
||||
// position on eyeball that matches iris radius
|
||||
float er = ( iris_radius / pState->peyeball->radius );
|
||||
er = FastSqrt( 1 - er * er );
|
||||
|
||||
// position on cornea sphere that matches iris radius
|
||||
float cr = ( iris_radius / cornea_radius );
|
||||
cr = FastSqrt( 1 - cr * cr );
|
||||
|
||||
float r = ( er * pState->peyeball->radius - cr * cornea_radius );
|
||||
VectorScale( pState->forward, r, cornea );
|
||||
|
||||
// get offset for center of cornea
|
||||
float dx, dy;
|
||||
dx = DotProduct( vright, cornea );
|
||||
dy = DotProduct( vup, cornea );
|
||||
|
||||
// move cornea to world space
|
||||
VectorAdd( cornea, pState->org, cornea );
|
||||
|
||||
Vector delta, intensity, reflection, coord;
|
||||
|
||||
// Put in glints due to the lights in the scene
|
||||
int nGlintCount = 0;
|
||||
for ( int i = 0; R_LightGlintPosition( i, cornea, delta, intensity ); ++i )
|
||||
{
|
||||
VectorNormalize( delta );
|
||||
if ( DotProduct( delta, pState->forward ) <= 0 )
|
||||
continue;
|
||||
|
||||
VectorAdd( delta, viewdelta, reflection );
|
||||
VectorNormalize( reflection );
|
||||
|
||||
pData[nGlintCount].m_vecPosition[0] = dx + cornea_radius * DotProduct( vright, reflection );
|
||||
pData[nGlintCount].m_vecPosition[1] = dy + cornea_radius * DotProduct( vup, reflection );
|
||||
pData[nGlintCount].m_vecIntensity = intensity;
|
||||
if ( ++nGlintCount >= nMaxGlints )
|
||||
return nMaxGlints;
|
||||
|
||||
if ( !R_LightGlintPosition( i, pState->org, delta, intensity ) )
|
||||
continue;
|
||||
|
||||
VectorNormalize( delta );
|
||||
if ( DotProduct( delta, pState->forward ) >= er )
|
||||
continue;
|
||||
|
||||
pData[nGlintCount].m_vecPosition[0] = pState->peyeball->radius * DotProduct( vright, reflection );
|
||||
pData[nGlintCount].m_vecPosition[1] = pState->peyeball->radius * DotProduct( vup, reflection );
|
||||
pData[nGlintCount].m_vecIntensity = intensity;
|
||||
if ( ++nGlintCount >= nMaxGlints )
|
||||
return nMaxGlints;
|
||||
}
|
||||
return nGlintCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders a glint texture procedurally
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture* CStudioRender::RenderGlintTexture( const eyeballstate_t *pState,
|
||||
const Vector& vright, const Vector& vup, const Vector& r_origin )
|
||||
{
|
||||
GlintRenderData_t pRenderData[16];
|
||||
int nGlintCount = BuildGlintRenderData( pRenderData, ARRAYSIZE(pRenderData),
|
||||
pState, vright, vup, r_origin );
|
||||
|
||||
if ( nGlintCount == 0 )
|
||||
return m_pGlintLODTexture;
|
||||
|
||||
// This could be done during the context of a flashlight rendering,
|
||||
// which could be setting the scissor rectangle. We need to save/restore this state
|
||||
// if ( m_pCurrentFlashlight )
|
||||
// {
|
||||
// DisableScissor();
|
||||
// }
|
||||
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
pRenderContext->PushRenderTargetAndViewport( m_pGlintTexture );
|
||||
|
||||
IMaterial *pPrevMaterial = pRenderContext->GetCurrentMaterial();
|
||||
void *pPrevProxy = pRenderContext->GetCurrentProxy();
|
||||
int nPrevBoneCount = pRenderContext->GetCurrentNumBones();
|
||||
MaterialHeightClipMode_t nPrevClipMode = pRenderContext->GetHeightClipMode( );
|
||||
bool bPrevClippingEnabled = pRenderContext->EnableClipping( false );
|
||||
bool bInFlashlightMode = pRenderContext->GetFlashlightMode();
|
||||
|
||||
// if ( bInFlashlightMode )
|
||||
// {
|
||||
// DisableScissor();
|
||||
// }
|
||||
pRenderContext->ClearColor4ub( 0, 0, 0, 0 );
|
||||
pRenderContext->ClearBuffers( true, false, false );
|
||||
|
||||
pRenderContext->SetFlashlightMode( false );
|
||||
pRenderContext->SetHeightClipMode( MATERIAL_HEIGHTCLIPMODE_DISABLE );
|
||||
pRenderContext->SetNumBoneWeights( 0 );
|
||||
pRenderContext->Bind( m_pGlintBuildMaterial );
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_MODEL );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nGlintCount * 4, nGlintCount * 6 );
|
||||
|
||||
Vector4D white( 1.0f, 1.0f, 1.0f, 1.0f );
|
||||
const float epsilon = 0.5f / 32.0f;
|
||||
int nIndex = 0;
|
||||
for ( int i = 0; i < nGlintCount; ++i )
|
||||
{
|
||||
const GlintRenderData_t &glint = pRenderData[i];
|
||||
|
||||
// Position of glint 0..31 range
|
||||
float x = (glint.m_vecPosition.x + 0.5f) * m_GlintWidth;
|
||||
float y = (glint.m_vecPosition.y + 0.5f) * m_GlintHeight;
|
||||
Vector vGlintCenter = Vector( x, y, 0.0f );
|
||||
float ooWidth = 1.0f / (float)m_GlintWidth;
|
||||
float ooHeight = 1.0f / (float)m_GlintHeight;
|
||||
|
||||
int x0 = floor(x);
|
||||
int y0 = floor(y);
|
||||
int x1 = x0 + 1.0f;
|
||||
int y1 = y0 + 1.0f;
|
||||
x0 -= 2.0f; // Fill rules make us pad this out more than the procedural version
|
||||
y0 -= 2.0f;
|
||||
|
||||
float screenX0 = x0 * 2 * ooWidth + epsilon - 1;
|
||||
float screenX1 = x1 * 2 * ooWidth + epsilon - 1;
|
||||
float screenY0 = -(y0 * 2 * ooHeight + epsilon - 1);
|
||||
float screenY1 = -(y1 * 2 * ooHeight + epsilon - 1);
|
||||
|
||||
meshBuilder.Position3f( screenX0, screenY0, 0.0f );
|
||||
meshBuilder.TexCoord2f( 0, x0, y0 );
|
||||
meshBuilder.TexCoord2fv( 1, vGlintCenter.Base() );
|
||||
meshBuilder.TexCoord3fv( 2, glint.m_vecIntensity.Base() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( screenX1, screenY0, 0.0f );
|
||||
meshBuilder.TexCoord2f( 0, x1, y0 );
|
||||
meshBuilder.TexCoord2fv( 1, vGlintCenter.Base() );
|
||||
meshBuilder.TexCoord3fv( 2, glint.m_vecIntensity.Base() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( screenX1, screenY1, 0.0f );
|
||||
meshBuilder.TexCoord2f( 0, x1, y1 );
|
||||
meshBuilder.TexCoord2fv( 1, vGlintCenter.Base() );
|
||||
meshBuilder.TexCoord3fv( 2, glint.m_vecIntensity.Base() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( screenX0, screenY1, 0.0f );
|
||||
meshBuilder.TexCoord2f( 0, x0, y1 );
|
||||
meshBuilder.TexCoord2fv( 1, vGlintCenter.Base() );
|
||||
meshBuilder.TexCoord3fv( 2, glint.m_vecIntensity.Base() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.FastIndex( nIndex );
|
||||
meshBuilder.FastIndex( nIndex+1 );
|
||||
meshBuilder.FastIndex( nIndex+2 );
|
||||
meshBuilder.FastIndex( nIndex );
|
||||
meshBuilder.FastIndex( nIndex+2 );
|
||||
meshBuilder.FastIndex( nIndex+3 );
|
||||
nIndex += 4;
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->DrawModulated( white );
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_MODEL );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
if ( IsX360() )
|
||||
{
|
||||
pRenderContext->CopyRenderTargetToTextureEx( m_pGlintTexture, 0, NULL, NULL );
|
||||
}
|
||||
|
||||
pRenderContext->PopRenderTargetAndViewport( );
|
||||
|
||||
pRenderContext->Bind( pPrevMaterial, pPrevProxy );
|
||||
pRenderContext->SetNumBoneWeights( nPrevBoneCount );
|
||||
pRenderContext->SetHeightClipMode( nPrevClipMode );
|
||||
pRenderContext->EnableClipping( bPrevClippingEnabled );
|
||||
pRenderContext->SetFlashlightMode( bInFlashlightMode );
|
||||
|
||||
// if ( m_pCurrentFlashlight )
|
||||
// {
|
||||
// EnableScissor( m_pCurrentFlashlight );
|
||||
// }
|
||||
|
||||
return m_pGlintTexture;
|
||||
}
|
||||
|
||||
static ConVar r_glint_procedural( "r_glint_procedural", "0" );
|
||||
static ConVar r_glint_alwaysdraw( "r_glint_alwaysdraw", "0" );
|
||||
|
||||
void CStudioRender::R_StudioEyeballGlint( const eyeballstate_t *pstate, IMaterialVar *pGlintVar,
|
||||
const Vector& vright, const Vector& vup, const Vector& r_origin )
|
||||
{
|
||||
// Kick off a PIX event, since this process encompasses a bunch of locks etc...
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
PIXEVENT( pRenderContext, "GenerateEyeballGlint" );
|
||||
|
||||
// Don't do a procedural glint texture if there are enough pixels covered by the eyeball onscreen,
|
||||
// and the eye isn't backfaced.
|
||||
if ( m_pGlintLODTexture && r_glint_alwaysdraw.GetInt() == 0 )
|
||||
{
|
||||
// backfaced or too small to bother?
|
||||
float pixelArea = pRenderContext->ComputePixelWidthOfSphere( pstate->org, pstate->peyeball->radius );
|
||||
if(
|
||||
// FIXME: this backface doesn't work for something that isn't a plane.
|
||||
// DotProduct( pstate->forward, m_ViewPlaneNormal ) > 0.0f ||
|
||||
pixelArea < m_pRC->m_Config.fEyeGlintPixelWidthLODThreshold )
|
||||
{
|
||||
// use black glint texture
|
||||
pGlintVar->SetTextureValue( m_pGlintLODTexture );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy method for DX8
|
||||
if ( !IsX360() && r_glint_procedural.GetInt() )
|
||||
{
|
||||
// Set up the texture regenerator
|
||||
s_GlintTextureRegen.m_pVRight = &vright;
|
||||
s_GlintTextureRegen.m_pVUp = &vup;
|
||||
s_GlintTextureRegen.m_pROrigin = &r_origin;
|
||||
s_GlintTextureRegen.m_pState = pstate;
|
||||
s_GlintTextureRegen.m_pStudioRender = this;
|
||||
|
||||
// This will cause the glint texture to be re-generated and then downloaded
|
||||
s_pProcGlint->Download( );
|
||||
|
||||
// This is necessary to make sure we don't reconstitute the bits
|
||||
// after coming back from a task switch
|
||||
s_GlintTextureRegen.m_pStudioRender = NULL;
|
||||
|
||||
// Use the normal glint instead of the black glint
|
||||
pGlintVar->SetTextureValue( s_pProcGlint );
|
||||
}
|
||||
else // Queued hardware version
|
||||
{
|
||||
// Make sure we know the correct size of the glint texture
|
||||
m_GlintWidth = m_pGlintTexture->GetActualWidth();
|
||||
m_GlintHeight = m_pGlintTexture->GetActualHeight();
|
||||
|
||||
// Render glint render target
|
||||
ITexture *pUseGlintTexture = RenderGlintTexture( pstate, vright, vup, r_origin );
|
||||
|
||||
// Use the normal glint instead of the black glint
|
||||
pGlintVar->SetTextureValue( pUseGlintTexture );
|
||||
}
|
||||
}
|
||||
|
||||
void CStudioRender::ComputeGlintTextureProjection( eyeballstate_t const* pState,
|
||||
const Vector& vright, const Vector& vup, matrix3x4_t& mat )
|
||||
{
|
||||
// project eyeball into screenspace texture
|
||||
float scale = 1.0 / (pState->peyeball->radius * 2);
|
||||
VectorScale( &vright.x, scale, mat[0] );
|
||||
VectorScale( &vup.x, scale, mat[1] );
|
||||
|
||||
mat[0][3] = -DotProduct( pState->org.Base(), mat[0] ) + 0.5;
|
||||
mat[1][3] = -DotProduct( pState->org.Base(), mat[1] ) + 0.5;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void R_MouthLighting( int count, const Vector *psrcverts, const Vector *psrcnorms, Vector4D *pdestlightvalues )
|
||||
{
|
||||
Vector forward;
|
||||
|
||||
if (m_pStudioHdr->nummouths < 1) return;
|
||||
|
||||
mstudiomouth_t *pMouth = r_pstudiohdr->pMouth( 0 ); // FIXME: this needs to get the mouth index from the shader
|
||||
|
||||
float fIllum = m_FlexWeights[pMouth->flexdesc];
|
||||
if (fIllum < 0) fIllum = 0;
|
||||
if (fIllum > 1) fIllum = 1;
|
||||
fIllum = LinearToTexture( fIllum ) / 255.0;
|
||||
|
||||
|
||||
VectorRotate( pMouth->forward, g_StudioInternalState.boneToWorld[ pMouth->bone ], forward );
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
float dot = -DotProduct( psrcnorms[i], forward );
|
||||
if (dot > 0)
|
||||
{
|
||||
dot = LinearToTexture( dot ) / 255.0; // FIXME: this isn't robust
|
||||
VectorScale( pdestlightvalues[i], dot, pdestlightvalues[i] );
|
||||
}
|
||||
else
|
||||
VectorFill( pdestlightvalues[i], 0 );
|
||||
|
||||
VectorScale( pdestlightvalues[i], fIllum, pdestlightvalues[i] );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void CStudioRender::R_MouthComputeLightingValues( float& fIllum, Vector& forward )
|
||||
{
|
||||
// FIXME: this needs to get the mouth index from the shader
|
||||
mstudiomouth_t *pMouth = m_pStudioHdr->pMouth( 0 );
|
||||
|
||||
fIllum = m_pFlexWeights[pMouth->flexdesc];
|
||||
if (fIllum < 0) fIllum = 0;
|
||||
if (fIllum > 1) fIllum = 1;
|
||||
fIllum = LinearToTexture( fIllum ) / 255.0;
|
||||
|
||||
VectorRotate( pMouth->forward, m_pBoneToWorld[ pMouth->bone ], forward );
|
||||
}
|
||||
|
||||
void CStudioRender::R_MouthLighting( float fIllum, const Vector& normal, const Vector& forward, Vector &light )
|
||||
{
|
||||
float dot = -DotProduct( normal, forward );
|
||||
if (dot > 0)
|
||||
{
|
||||
VectorScale( light, dot * fIllum, light );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorFill( light, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int illumVarCache = 0;
|
||||
static unsigned int forwardVarCache = 0;
|
||||
void CStudioRender::R_MouthSetupVertexShader( IMaterial* pMaterial )
|
||||
{
|
||||
if (!pMaterial)
|
||||
return;
|
||||
|
||||
// FIXME: this needs to get the mouth index from the shader
|
||||
mstudiomouth_t *pMouth = m_pStudioHdr->pMouth( 0 );
|
||||
|
||||
// Don't deal with illum gamma, we apply it at a different point for vertex shaders
|
||||
float fIllum = m_pFlexWeights[pMouth->flexdesc];
|
||||
if (fIllum < 0) fIllum = 0;
|
||||
if (fIllum > 1) fIllum = 1;
|
||||
|
||||
Vector forward;
|
||||
VectorRotate( pMouth->forward, m_pBoneToWorld[ pMouth->bone ], forward );
|
||||
forward *= -1;
|
||||
|
||||
IMaterialVar* pIllumVar = pMaterial->FindVarFast( "$illumfactor", &illumVarCache );
|
||||
if (pIllumVar)
|
||||
{
|
||||
pIllumVar->SetFloatValue( fIllum );
|
||||
}
|
||||
|
||||
IMaterialVar* pFowardVar = pMaterial->FindVarFast( "$forward", &forwardVarCache );
|
||||
if (pFowardVar)
|
||||
{
|
||||
pFowardVar->SetVecValue( forward.Base(), 3 );
|
||||
}
|
||||
}
|
||||
143
studiorender/r_studiogettriangles.cpp
Normal file
143
studiorender/r_studiogettriangles.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
//===== Copyright <20> 1996-2008, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "studiorendercontext.h"
|
||||
#include "optimize.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void CStudioRenderContext::GetTriangles( const DrawModelInfo_t& info, matrix3x4_t *pBoneToWorld, GetTriangles_Output_t &out )
|
||||
{
|
||||
VPROF( "CStudioRender::GetTriangles");
|
||||
|
||||
out.m_MaterialBatches.RemoveAll(); // clear out data.
|
||||
|
||||
if( !info.m_pStudioHdr || !info.m_pHardwareData || !info.m_pHardwareData->m_NumLODs || !info.m_pHardwareData->m_pLODs )
|
||||
return;
|
||||
|
||||
int lod = info.m_Lod;
|
||||
int lastlod = info.m_pHardwareData->m_NumLODs - 1;
|
||||
lod = lod == USESHADOWLOD ? lastlod : clamp( lod, 0, lastlod );
|
||||
|
||||
// clamp to root lod
|
||||
if ( lod < info.m_pHardwareData->m_RootLOD )
|
||||
{
|
||||
lod = info.m_pHardwareData->m_RootLOD;
|
||||
}
|
||||
|
||||
int nSkin = info.m_Skin;
|
||||
if ( nSkin >= info.m_pStudioHdr->numskinfamilies )
|
||||
{
|
||||
nSkin = 0;
|
||||
}
|
||||
short *pSkinRef = info.m_pStudioHdr->pSkinref( nSkin * info.m_pStudioHdr->numskinref );
|
||||
|
||||
studiomeshdata_t *pStudioMeshes = info.m_pHardwareData->m_pLODs[lod].m_pMeshData;
|
||||
IMaterial **ppMaterials = info.m_pHardwareData->m_pLODs[lod].ppMaterials;
|
||||
|
||||
// Bone to world must be set before calling this function; it uses it here
|
||||
int boneMask = BONE_USED_BY_VERTEX_AT_LOD(lod);
|
||||
ComputePoseToWorld( out.m_PoseToWorld, info.m_pStudioHdr, boneMask, m_RC.m_ViewOrigin, pBoneToWorld );
|
||||
|
||||
int i;
|
||||
for ( i=0 ; i < info.m_pStudioHdr->numbodyparts ; i++ )
|
||||
{
|
||||
mstudiomodel_t *pModel = NULL;
|
||||
R_StudioSetupModel( i, info.m_Body, &pModel, info.m_pStudioHdr );
|
||||
|
||||
// Iterate over all the meshes.... each mesh is a new material
|
||||
int k;
|
||||
for ( k = 0; k < pModel->nummeshes; ++k )
|
||||
{
|
||||
GetTriangles_MaterialBatch_t &materialBatch = out.m_MaterialBatches[out.m_MaterialBatches.AddToTail()];
|
||||
mstudiomesh_t *pMesh = pModel->pMesh(k);
|
||||
|
||||
if ( !pModel->CacheVertexData( info.m_pStudioHdr ) )
|
||||
{
|
||||
// not available yet
|
||||
continue;
|
||||
}
|
||||
const mstudio_meshvertexdata_t *vertData = pMesh->GetVertexData( info.m_pStudioHdr );
|
||||
Assert( vertData ); // This can only return NULL on X360 for now
|
||||
|
||||
// add the verts from this mesh to the materialBatch
|
||||
materialBatch.m_Verts.SetCount( pMesh->numvertices );
|
||||
for ( int vertID = 0; vertID < pMesh->numvertices; vertID++ )
|
||||
{
|
||||
GetTriangles_Vertex_t& vert = materialBatch.m_Verts[vertID];
|
||||
|
||||
vert.m_Position = *vertData->Position( vertID );
|
||||
vert.m_Normal = *vertData->Normal( vertID );
|
||||
vert.m_TexCoord = *vertData->Texcoord( vertID );
|
||||
|
||||
if (vertData->HasTangentData())
|
||||
{
|
||||
vert.m_TangentS = *vertData->TangentS( vertID );
|
||||
}
|
||||
#if _DEBUG
|
||||
else
|
||||
{
|
||||
// ensure any unintended access faults
|
||||
vert.m_TangentS.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
|
||||
}
|
||||
#endif
|
||||
vert.m_NumBones = vertData->BoneWeights( vertID )->numbones;
|
||||
int j;
|
||||
for ( j = 0; j < vert.m_NumBones; j++ )
|
||||
{
|
||||
vert.m_BoneWeight[j] = vertData->BoneWeights( vertID )->weight[j];
|
||||
vert.m_BoneIndex[j] = vertData->BoneWeights( vertID )->bone[j];
|
||||
}
|
||||
}
|
||||
|
||||
IMaterial *pMaterial = ppMaterials[pSkinRef[pMesh->material]];
|
||||
Assert( pMaterial );
|
||||
materialBatch.m_pMaterial = pMaterial;
|
||||
studiomeshdata_t *pMeshData = &pStudioMeshes[pMesh->meshid];
|
||||
if ( pMeshData->m_NumGroup == 0 )
|
||||
continue;
|
||||
|
||||
// Clear out indices
|
||||
materialBatch.m_TriListIndices.SetCount( 0 );
|
||||
|
||||
// Iterate over all stripgroups
|
||||
int stripGroupID;
|
||||
for ( stripGroupID = 0; stripGroupID < pMeshData->m_NumGroup; stripGroupID++ )
|
||||
{
|
||||
studiomeshgroup_t *pMeshGroup = &pMeshData->m_pMeshGroup[stripGroupID];
|
||||
// bool bIsFlexed = ( pMeshGroup->m_Flags & MESHGROUP_IS_FLEXED ) != 0;
|
||||
// bool bIsHWSkinned = ( pMeshGroup->m_Flags & MESHGROUP_IS_HWSKINNED ) != 0;
|
||||
|
||||
// Iterate over all strips. . . each strip potentially changes bones states.
|
||||
int stripID;
|
||||
for ( stripID = 0; stripID < pMeshGroup->m_NumStrips; stripID++ )
|
||||
{
|
||||
OptimizedModel::StripHeader_t *pStripData = &pMeshGroup->m_pStripData[stripID];
|
||||
// int boneID;
|
||||
// for( boneID = 0; boneID < pStripData->numBoneStateChanges; boneID++ )
|
||||
// {
|
||||
// OptimizedModel::BoneStateChangeHeader_t *pBoneStateChange = pStripData->pBoneStateChange( boneID );
|
||||
// hardwareBoneToGlobalBone[pBoneStateChange->hardwareID] = pBoneStateChange->newBoneID;
|
||||
// }
|
||||
|
||||
// JasonM TODO: check for case where pStripData->flags & OptimizedModel::STRIP_IS_QUADLIST
|
||||
|
||||
for ( int i = 0; i < pStripData->numIndices; i += 3 )
|
||||
{
|
||||
int idx = pStripData->indexOffset + i;
|
||||
materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx ) );
|
||||
materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 1 ) );
|
||||
materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 2 ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
542
studiorender/r_studiolight.cpp
Normal file
542
studiorender/r_studiolight.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
//===== Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "r_studiolight.h"
|
||||
#include "studiorender.h"
|
||||
#include "studiorendercontext.h"
|
||||
#include "studio.h"
|
||||
#include "materialsystem/imaterialsystemhardwareconfig.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include <float.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
void R_WorldLightDelta( const LightDesc_t *wl, const Vector& org, Vector& delta );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copies lighting state
|
||||
//-----------------------------------------------------------------------------
|
||||
int CopyLocalLightingState( int nMaxLights, LightDesc_t *pDest, int nLightCount, const LightDesc_t *pSrc )
|
||||
{
|
||||
// ensure we write within array bounds
|
||||
if ( nLightCount > nMaxLights )
|
||||
{
|
||||
nLightCount = nMaxLights;
|
||||
}
|
||||
|
||||
for( int i = 0; i < nLightCount; i++ )
|
||||
{
|
||||
LightDesc_t *pLight = &pDest[i];
|
||||
memcpy( pLight, &pSrc[i], sizeof( LightDesc_t ) );
|
||||
pLight->m_Flags = 0;
|
||||
if( pLight->m_Attenuation0 != 0.0f )
|
||||
{
|
||||
pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0;
|
||||
}
|
||||
if( pLight->m_Attenuation1 != 0.0f )
|
||||
{
|
||||
pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1;
|
||||
}
|
||||
if( pLight->m_Attenuation2 != 0.0f )
|
||||
{
|
||||
pLight->m_Flags |= LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2;
|
||||
}
|
||||
}
|
||||
|
||||
return nLightCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes the ambient term
|
||||
//-----------------------------------------------------------------------------
|
||||
void R_LightAmbient_4D( const Vector& normal, Vector4D* pLightBoxColor, Vector &lv )
|
||||
{
|
||||
VectorScale( normal[0] > 0.f ? pLightBoxColor[0].AsVector3D() : pLightBoxColor[1].AsVector3D(), normal[0]*normal[0], lv );
|
||||
VectorMA( lv, normal[1]*normal[1], normal[1] > 0.f ? pLightBoxColor[2].AsVector3D() : pLightBoxColor[3].AsVector3D(), lv );
|
||||
VectorMA( lv, normal[2]*normal[2], normal[2] > 0.f ? pLightBoxColor[4].AsVector3D() : pLightBoxColor[5].AsVector3D(), lv );
|
||||
}
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
void R_LightAmbient_4D( const FourVectors& normal, Vector4D* pLightBoxColor, FourVectors &lv )
|
||||
{
|
||||
// VPROF( "R_LightAmbient" );
|
||||
|
||||
// !!speed!! compute ambient color cube in sse format
|
||||
static fltx4 FourZeros={0.,0.,0.,.0};
|
||||
|
||||
// find the contributions from each axis
|
||||
fltx4 NegMask=CmpLtSIMD(normal.x,FourZeros);
|
||||
fltx4 ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().x);
|
||||
fltx4 ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().x);
|
||||
fltx4 DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
fltx4 NormCompSquared=MulSIMD(normal.x,normal.x);
|
||||
lv.x=MulSIMD(DirectionalColor,NormCompSquared);
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().y);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().y);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.y=MulSIMD(DirectionalColor,NormCompSquared);
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[0].AsVector3D().z);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[1].AsVector3D().z);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.z=MulSIMD(DirectionalColor,NormCompSquared);
|
||||
|
||||
NegMask=CmpLtSIMD(normal.y,FourZeros);
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().x);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().x);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
NormCompSquared=MulSIMD(normal.y,normal.y);
|
||||
lv.x=AddSIMD(lv.x,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().y);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().y);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.y=AddSIMD(lv.y,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[2].AsVector3D().z);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[3].AsVector3D().z);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.z=AddSIMD(lv.z,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
|
||||
NegMask=CmpLtSIMD(normal.z,FourZeros);
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().x);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().x);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
NormCompSquared=MulSIMD(normal.z,normal.z);
|
||||
lv.x=AddSIMD(lv.x,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().y);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().y);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.y=AddSIMD(lv.y,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
ColorSelect0=ReplicateX4(pLightBoxColor[4].AsVector3D().z);
|
||||
ColorSelect1=ReplicateX4(pLightBoxColor[5].AsVector3D().z);
|
||||
DirectionalColor=OrSIMD(AndSIMD(ColorSelect1,NegMask),AndNotSIMD(NegMask,ColorSelect0));
|
||||
lv.z=AddSIMD(lv.z,MulSIMD(DirectionalColor,NormCompSquared));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes the ambient term, parameters are 3D Vectors for optimization
|
||||
//-----------------------------------------------------------------------------
|
||||
void R_LightAmbient_3D( const Vector& normal, const Vector* pLightBoxColor, Vector &lv )
|
||||
{
|
||||
VectorScale( normal[0] > 0.f ? pLightBoxColor[0] : pLightBoxColor[1], normal[0]*normal[0], lv );
|
||||
VectorMA( lv, normal[1]*normal[1], normal[1] > 0.f ? pLightBoxColor[2] : pLightBoxColor[3], lv );
|
||||
VectorMA( lv, normal[2]*normal[2], normal[2] > 0.f ? pLightBoxColor[4] : pLightBoxColor[5], lv );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set up light[i].dot, light[i].falloff, and light[i].delta for all lights given
|
||||
// a vertex position "vert".
|
||||
//-----------------------------------------------------------------------------
|
||||
void R_LightStrengthWorld( const Vector& vert, int lightcount, LightDesc_t* pDesc, lightpos_t *light )
|
||||
{
|
||||
// VPROF( "R_LightStrengthWorld" );
|
||||
|
||||
// NJS: note to self, maybe switch here based on lightcount, so multiple squareroots can be done simeltaneously?
|
||||
for ( int i = 0; i < lightcount; i++)
|
||||
{
|
||||
R_WorldLightDelta( &pDesc[i], vert, light[i].delta );
|
||||
light[i].falloff = R_WorldLightDistanceFalloff( &pDesc[i], light[i].delta );
|
||||
|
||||
VectorNormalizeFast( light[i].delta );
|
||||
light[i].dot = DotProduct( light[i].delta, pDesc[i].m_Direction );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Calculate the delta between a light and position
|
||||
//-----------------------------------------------------------------------------
|
||||
void R_WorldLightDelta( const LightDesc_t *wl, const Vector& org, Vector& delta )
|
||||
{
|
||||
switch (wl->m_Type)
|
||||
{
|
||||
case MATERIAL_LIGHT_POINT:
|
||||
case MATERIAL_LIGHT_SPOT:
|
||||
VectorSubtract( wl->m_Position, org, delta );
|
||||
break;
|
||||
|
||||
case MATERIAL_LIGHT_DIRECTIONAL:
|
||||
VectorMultiply( wl->m_Direction, -1, delta );
|
||||
break;
|
||||
|
||||
default:
|
||||
// Bug: need to return an error
|
||||
Assert( 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//#define NO_AMBIENT_CUBE 1
|
||||
#define LIGHT_EFFECTS_FUNCTABLE_SIZE 256
|
||||
|
||||
// TODO: cone clipping calc's wont work for boxlight since the player asks for a single point. Not sure what the volume is.
|
||||
TEMPLATE_FUNCTION_TABLE( void, R_LightEffectsWorldFunctionTable, ( const LightDesc_t* pLightDesc, const lightpos_t *light, const Vector& normal, Vector &dest ), LIGHT_EFFECTS_FUNCTABLE_SIZE )
|
||||
{
|
||||
enum
|
||||
{
|
||||
LightType1 = ( nArgument & 0xC0 ) >> 6,
|
||||
LightType2 = ( nArgument & 0x30 ) >> 4,
|
||||
LightType3 = ( nArgument & 0x0C ) >> 2,
|
||||
LightType4 = ( nArgument & 0x03 )
|
||||
};
|
||||
|
||||
// VPROF( "R_LightEffectsWorld" );
|
||||
|
||||
#ifdef NO_AMBIENT_CUBE
|
||||
dest[0] = dest[1] = dest[2] = 0.0f;
|
||||
#endif
|
||||
|
||||
// FIXME: lighting effects for normal and position are independent!
|
||||
// FIXME: these can be pre-calculated per normal
|
||||
if( (int)LightType1 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[0].falloff * CWorldLightAngleWrapper<LightType1>::WorldLightAngle( &pLightDesc[0], pLightDesc[0].m_Direction, normal, light[0].delta );
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[0].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType2 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[1].falloff * CWorldLightAngleWrapper<LightType2>::WorldLightAngle( &pLightDesc[1], pLightDesc[1].m_Direction, normal, light[1].delta );
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[1].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType3 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[2].falloff * CWorldLightAngleWrapper<LightType3>::WorldLightAngle( &pLightDesc[2], pLightDesc[2].m_Direction, normal, light[2].delta );
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[2].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType4 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[3].falloff * CWorldLightAngleWrapper<LightType4>::WorldLightAngle( &pLightDesc[3], pLightDesc[3].m_Direction, normal, light[3].delta );
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[3].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEMPLATE_FUNCTION_TABLE( void, R_LightEffectsWorldFunctionTableConstDirectional, ( const LightDesc_t* pLightDesc, const lightpos_t *light, const Vector& normal, Vector &dest, float flDirectionalConstant ), LIGHT_EFFECTS_FUNCTABLE_SIZE )
|
||||
{
|
||||
enum
|
||||
{
|
||||
LightType1 = ( nArgument & 0xC0 ) >> 6,
|
||||
LightType2 = ( nArgument & 0x30 ) >> 4,
|
||||
LightType3 = ( nArgument & 0x0C ) >> 2,
|
||||
LightType4 = ( nArgument & 0x03 )
|
||||
};
|
||||
|
||||
// VPROF( "R_LightEffectsWorld" );
|
||||
|
||||
#ifdef NO_AMBIENT_CUBE
|
||||
dest[0] = dest[1] = dest[2] = 0.0f;
|
||||
#endif
|
||||
|
||||
// FIXME: lighting effects for normal and position are independent!
|
||||
// FIXME: these can be pre-calculated per normal
|
||||
if( (int)LightType1 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[0].falloff *
|
||||
CWorldLightAngleWrapperConstDirectional<LightType1>::WorldLightAngle( &pLightDesc[0],
|
||||
pLightDesc[0].m_Direction, normal, light[0].delta, flDirectionalConstant );
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[0].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType2 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[1].falloff *
|
||||
CWorldLightAngleWrapperConstDirectional<LightType2>::WorldLightAngle( &pLightDesc[1],
|
||||
pLightDesc[1].m_Direction, normal, light[1].delta, flDirectionalConstant );
|
||||
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[1].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType3 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[2].falloff *
|
||||
CWorldLightAngleWrapperConstDirectional<LightType3>::WorldLightAngle( &pLightDesc[2],
|
||||
pLightDesc[2].m_Direction, normal, light[2].delta, flDirectionalConstant );
|
||||
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[2].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
|
||||
if( (int)LightType4 != (int)MATERIAL_LIGHT_DISABLE )
|
||||
{
|
||||
float ratio = light[3].falloff *
|
||||
CWorldLightAngleWrapperConstDirectional<LightType4>::WorldLightAngle( &pLightDesc[3],
|
||||
pLightDesc[3].m_Direction, normal, light[3].delta, flDirectionalConstant );
|
||||
|
||||
if (ratio > 0)
|
||||
{
|
||||
const float* pColor = (float*)&pLightDesc[3].m_Color;
|
||||
dest[0] += pColor[0] * ratio;
|
||||
dest[1] += pColor[1] * ratio;
|
||||
dest[2] += pColor[2] * ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Get the function table index
|
||||
//-----------------------------------------------------------------------------
|
||||
static int s_pLightMask[ 5 ] =
|
||||
{
|
||||
0, // No lights
|
||||
0xC0, // 1 light
|
||||
0xF0, // 2 lights
|
||||
0xFC, // 3 lights
|
||||
0xFF, // 4 lights
|
||||
};
|
||||
|
||||
inline int R_LightEffectsWorldIndex(const LightDesc_t* pLightDesc, int nNumLights)
|
||||
{
|
||||
if ( nNumLights > 4 )
|
||||
{
|
||||
nNumLights = 4;
|
||||
}
|
||||
|
||||
int nIndex = ((pLightDesc[0].m_Type & 0x3) << 6) | ((pLightDesc[1].m_Type & 0x3) << 4) | ( (pLightDesc[2].m_Type & 0x3) << 2) | (pLightDesc[3].m_Type & 0x3);
|
||||
nIndex &= s_pLightMask[ nNumLights ];
|
||||
|
||||
Assert( nIndex >= 0 && nIndex < R_LightEffectsWorldFunctionTable::count );
|
||||
return nIndex;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
light_direction (light_pos - vertex_pos)
|
||||
*/
|
||||
// TODO: move cone calcs to position
|
||||
// TODO: cone clipping calc's wont work for boxlight since the player asks for a single point. Not sure what the volume is.
|
||||
TEMPLATE_FUNCTION_TABLE( float, R_WorldLightDistanceFalloffFunctionTable, ( const LightDesc_t *wl, const Vector& delta ), 8)
|
||||
{
|
||||
Assert( nArgument != 0 );
|
||||
|
||||
float dist2 = DotProduct( delta, delta );
|
||||
|
||||
// Cull out light beyond this radius
|
||||
if (wl->m_Range != 0.f)
|
||||
{
|
||||
if (dist2 > wl->m_Range * wl->m_Range)
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// The general purpose equation:
|
||||
float fTotal = FLT_EPSILON;
|
||||
|
||||
if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
|
||||
{
|
||||
fTotal = wl->m_Attenuation0;
|
||||
}
|
||||
|
||||
if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
|
||||
{
|
||||
fTotal += wl->m_Attenuation1 * FastSqrt( dist2 );
|
||||
}
|
||||
|
||||
if( nArgument & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
|
||||
{
|
||||
fTotal += wl->m_Attenuation2 * dist2;
|
||||
}
|
||||
|
||||
return 1.0f / fTotal;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Calculate the falloff from the world lights
|
||||
//-----------------------------------------------------------------------------
|
||||
float FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const Vector& delta )
|
||||
{
|
||||
// Ensure no invalid flags are set
|
||||
Assert( ! ( wl->m_Flags & ~(LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2|LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED) ) );
|
||||
|
||||
// calculate falloff
|
||||
int flags = wl->m_Flags & (LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2);
|
||||
return R_WorldLightDistanceFalloffFunctionTable::functions[flags](wl, delta);
|
||||
}
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
fltx4 FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const FourVectors &delta )
|
||||
{
|
||||
// !!speed!!: lights could store m_Attenuation2,m_Attenuation1, and m_Range^2 copies in replicated SSE format.
|
||||
|
||||
// Ensure no invalid flags are set
|
||||
Assert( ! ( wl->m_Flags & ~(LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1|LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2|LIGHTTYPE_OPTIMIZATIONFLAGS_DERIVED_VALUES_CALCED) ) );
|
||||
|
||||
fltx4 dist2 = delta*delta;
|
||||
|
||||
fltx4 fTotal;
|
||||
|
||||
if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0 )
|
||||
{
|
||||
fTotal = ReplicateX4(wl->m_Attenuation0);
|
||||
}
|
||||
else
|
||||
fTotal= ReplicateX4(FLT_EPSILON); // !!speed!! replicate
|
||||
|
||||
if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION1 )
|
||||
{
|
||||
fTotal=AddSIMD(fTotal,MulSIMD(ReplicateX4(wl->m_Attenuation1),SqrtEstSIMD(dist2)));
|
||||
}
|
||||
|
||||
if( wl->m_Flags & LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION2 )
|
||||
{
|
||||
fTotal=AddSIMD(fTotal,MulSIMD(ReplicateX4(wl->m_Attenuation2),dist2));
|
||||
}
|
||||
|
||||
fTotal=ReciprocalEstSIMD(fTotal);
|
||||
// Cull out light beyond this radius
|
||||
// now, zero out elements for which dist2 was > range^2. !!speed!! lights should store dist^2 in sse format
|
||||
if (wl->m_Range != 0.f)
|
||||
{
|
||||
fltx4 RangeSquared = ReplicateX4(wl->m_Range*wl->m_Range); // !!speed!!
|
||||
fTotal=AndSIMD(fTotal,CmpLtSIMD(dist2,RangeSquared));
|
||||
}
|
||||
return fTotal;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int CStudioRender::R_LightGlintPosition( int index, const Vector& org, Vector& delta, Vector& intensity )
|
||||
{
|
||||
if (index >= m_pRC->m_NumLocalLights)
|
||||
return false;
|
||||
|
||||
R_WorldLightDelta( &m_pRC->m_LocalLights[index], org, delta );
|
||||
float falloff = R_WorldLightDistanceFalloff( &m_pRC->m_LocalLights[index], delta );
|
||||
|
||||
VectorMultiply( m_pRC->m_LocalLights[index].m_Color, falloff, intensity );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Setup up the function table
|
||||
//-----------------------------------------------------------------------------
|
||||
void CStudioRender::R_InitLightEffectsWorld3()
|
||||
{
|
||||
// set the function pointer
|
||||
int index = R_LightEffectsWorldIndex( m_pRC->m_LocalLights, m_pRC->m_NumLocalLights );
|
||||
R_LightEffectsWorld3 = R_LightEffectsWorldFunctionTable::functions[index];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Performs lighting functions common to the ComputeLighting and ComputeLightingConstantDirectional
|
||||
// returns the index of the LightEffectsWorldFunction to use
|
||||
//-----------------------------------------------------------------------------
|
||||
static int ComputeLightingCommon( const Vector* pAmbient, int lightCount,
|
||||
LightDesc_t* pLights, const Vector& pt, const Vector& normal, lightpos_t *pLightPos, Vector& lighting )
|
||||
{
|
||||
// Set up lightpos[i].dot, lightpos[i].falloff, and lightpos[i].delta for all lights
|
||||
R_LightStrengthWorld( pt, lightCount, pLights, pLightPos );
|
||||
|
||||
// calculate ambient values from the ambient cube given a normal.
|
||||
R_LightAmbient_3D( normal, pAmbient, lighting );
|
||||
|
||||
return R_LightEffectsWorldIndex( pLights, lightCount );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute the lighting at a point and normal
|
||||
// Final Lighting is in linear space
|
||||
//-----------------------------------------------------------------------------
|
||||
void CStudioRenderContext::ComputeLighting( const Vector* pAmbient, int lightCount,
|
||||
LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting )
|
||||
{
|
||||
if ( m_RC.m_Config.fullbright )
|
||||
{
|
||||
lighting.Init( 1.0f, 1.0f, 1.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lightCount > ARRAYSIZE( m_pLightPos ) )
|
||||
{
|
||||
AssertMsg( 0, "Light count out of range in ComputeLighting\n" );
|
||||
lightCount = ARRAYSIZE( m_pLightPos );
|
||||
}
|
||||
|
||||
// Calculate color given lightpos_t lightpos, a normal, and the ambient
|
||||
// color from the ambient cube calculated in ComputeLightingCommon
|
||||
int index = ComputeLightingCommon( pAmbient, lightCount, pLights, pt, normal, m_pLightPos, lighting );
|
||||
R_LightEffectsWorldFunctionTable::functions[index]( pLights, m_pLightPos, normal, lighting );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute the lighting at a point and normal
|
||||
// Final Lighting is in linear space
|
||||
// Uses flDirectionalAmount instead of directional components of lights
|
||||
//-----------------------------------------------------------------------------
|
||||
void CStudioRenderContext::ComputeLightingConstDirectional( const Vector* pAmbient, int lightCount,
|
||||
LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount )
|
||||
{
|
||||
if ( m_RC.m_Config.fullbright )
|
||||
{
|
||||
lighting.Init( 1.0f, 1.0f, 1.0f );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( lightCount > ARRAYSIZE( m_pLightPos ) )
|
||||
{
|
||||
AssertMsg( 0, "Light count out of range in ComputeLighting\n" );
|
||||
lightCount = ARRAYSIZE( m_pLightPos );
|
||||
}
|
||||
|
||||
// Calculate color given lightpos_t lightpos, a normal, and the ambient
|
||||
// color from the ambient cube calculated in ComputeLightingCommon
|
||||
int index = ComputeLightingCommon( pAmbient, lightCount, pLights, pt, normal, m_pLightPos, lighting );
|
||||
R_LightEffectsWorldFunctionTableConstDirectional::functions[index]( pLights, m_pLightPos, normal, lighting, flDirectionalAmount );
|
||||
}
|
||||
49
studiorender/r_studiolight.h
Normal file
49
studiorender/r_studiolight.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Stateless light computation routines
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef R_STUDIOLIGHT_H
|
||||
#define R_STUDIOLIGHT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tier0/platform.h"
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class Vector;
|
||||
class Vector4D;
|
||||
class FourVectors;
|
||||
struct lightpos_t;
|
||||
struct LightDesc_t;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Stateless light computation routines
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Computes the ambient term
|
||||
void R_LightAmbient_4D( const Vector& normal, Vector4D* pLightBoxColor, Vector &lv );
|
||||
void R_LightStrengthWorld( const Vector& vert, int lightcount, LightDesc_t* pLightDesc, lightpos_t *light );
|
||||
float FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const Vector& delta );
|
||||
|
||||
// Copies lighting state into a buffer, returns number of lights copied
|
||||
int CopyLocalLightingState( int nMaxLights, LightDesc_t *pDest, int nLightCount, const LightDesc_t *pSrc );
|
||||
|
||||
#if defined( _WIN32 ) && !defined( _X360 )
|
||||
// SSE optimized versions
|
||||
void R_LightAmbient_4D( const FourVectors& normal, Vector4D* pLightBoxColor, FourVectors &lv );
|
||||
__m128 FASTCALL R_WorldLightDistanceFalloff( const LightDesc_t *wl, const FourVectors& delta );
|
||||
#endif
|
||||
|
||||
#endif // R_STUDIOLIGHT_H
|
||||
659
studiorender/r_studiosubd.cpp
Normal file
659
studiorender/r_studiosubd.cpp
Normal file
@@ -0,0 +1,659 @@
|
||||
//===== Copyright (c) 1996-2008, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: Support for mapping from a quad mesh to Bicubic Patches, as a means
|
||||
// of rendering approximate Catmull-Clark subdivision surfaces
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "studio.h"
|
||||
#include "studiorendercontext.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "materialsystem/itexture.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "studiorender.h"
|
||||
#include "optimize.h"
|
||||
#include "tier1/convar.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#define R_STUDIOSUBD
|
||||
#include "r_studiosubd_patches.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Temporary debug arrays
|
||||
extern CUtlVector<Vector4D> g_DebugCornerPositions;
|
||||
extern CUtlVector<Vector4D> g_DebugEdgePositions;
|
||||
extern CUtlVector<Vector4D> g_DebugInteriorPositions;
|
||||
#endif
|
||||
|
||||
//
|
||||
// Check out CL# 584588 for an SSE-ized version of the older versions of these
|
||||
// routines, which came from an older MS doc, by way of the DX10 SDK
|
||||
//
|
||||
|
||||
static void R_TransformVert( const Vector *pSrcPos, matrix3x4_t *pSkinMat, Vector4DAligned &pos )
|
||||
{
|
||||
VPROF_BUDGET( "R_TransformVert", _T("SubD Rendering") );
|
||||
|
||||
// NOTE: Could add SSE stuff here, if we knew what SSE stuff could make it faster
|
||||
pos.x = pSrcPos->x * (*pSkinMat)[0][0] + pSrcPos->y * (*pSkinMat)[0][1] + pSrcPos->z * (*pSkinMat)[0][2] + (*pSkinMat)[0][3];
|
||||
pos.y = pSrcPos->x * (*pSkinMat)[1][0] + pSrcPos->y * (*pSkinMat)[1][1] + pSrcPos->z * (*pSkinMat)[1][2] + (*pSkinMat)[1][3];
|
||||
pos.z = pSrcPos->x * (*pSkinMat)[2][0] + pSrcPos->y * (*pSkinMat)[2][1] + pSrcPos->z * (*pSkinMat)[2][2] + (*pSkinMat)[2][3];
|
||||
pos.w = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
// This function is duplicate code ****
|
||||
static matrix3x4_t *ComputeSkinMatrixSSE( mstudioboneweight_t &boneweights, matrix3x4_t *pPoseToWorld, matrix3x4_t &scratchMatrix )
|
||||
{
|
||||
VPROF_BUDGET( "ComputeSkinMatrixSSE", _T("SubD Rendering") );
|
||||
|
||||
// NOTE: pPoseToWorld, being cache aligned, doesn't need explicit initialization
|
||||
#if defined( _WIN32 ) && !defined( WIN64 ) && !defined( _X360 )
|
||||
switch( boneweights.numbones )
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
return &pPoseToWorld[boneweights.bone[0]];
|
||||
|
||||
case 2:
|
||||
{
|
||||
matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
|
||||
matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
|
||||
float *pWeights = boneweights.weight;
|
||||
|
||||
_asm
|
||||
{
|
||||
mov eax, DWORD PTR [pWeights]
|
||||
movss xmm6, dword ptr[eax] ; boneweights.weight[0]
|
||||
movss xmm7, dword ptr[eax + 4] ; boneweights.weight[1]
|
||||
|
||||
mov eax, DWORD PTR [boneMat0]
|
||||
mov ecx, DWORD PTR [boneMat1]
|
||||
mov edi, DWORD PTR [scratchMatrix]
|
||||
|
||||
// Fill xmm6, and 7 with all the bone weights
|
||||
shufps xmm6, xmm6, 0
|
||||
shufps xmm7, xmm7, 0
|
||||
|
||||
// Load up all rows of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax]
|
||||
movaps xmm1, XMMWORD PTR [ecx]
|
||||
movaps xmm2, XMMWORD PTR [eax + 16]
|
||||
movaps xmm3, XMMWORD PTR [ecx + 16]
|
||||
movaps xmm4, XMMWORD PTR [eax + 32]
|
||||
movaps xmm5, XMMWORD PTR [ecx + 32]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm6
|
||||
mulps xmm1, xmm7
|
||||
mulps xmm2, xmm6
|
||||
mulps xmm3, xmm7
|
||||
mulps xmm4, xmm6
|
||||
mulps xmm5, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm2, xmm3
|
||||
addps xmm4, xmm5
|
||||
|
||||
movaps XMMWORD PTR [edi], xmm0
|
||||
movaps XMMWORD PTR [edi + 16], xmm2
|
||||
movaps XMMWORD PTR [edi + 32], xmm4
|
||||
}
|
||||
}
|
||||
return &scratchMatrix;
|
||||
|
||||
case 3:
|
||||
{
|
||||
matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
|
||||
matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
|
||||
matrix3x4_t &boneMat2 = pPoseToWorld[boneweights.bone[2]];
|
||||
float *pWeights = boneweights.weight;
|
||||
|
||||
_asm
|
||||
{
|
||||
mov eax, DWORD PTR [pWeights]
|
||||
movss xmm5, dword ptr[eax] ; boneweights.weight[0]
|
||||
movss xmm6, dword ptr[eax + 4] ; boneweights.weight[1]
|
||||
movss xmm7, dword ptr[eax + 8] ; boneweights.weight[2]
|
||||
|
||||
mov eax, DWORD PTR [boneMat0]
|
||||
mov ecx, DWORD PTR [boneMat1]
|
||||
mov edx, DWORD PTR [boneMat2]
|
||||
mov edi, DWORD PTR [scratchMatrix]
|
||||
|
||||
// Fill xmm5, 6, and 7 with all the bone weights
|
||||
shufps xmm5, xmm5, 0
|
||||
shufps xmm6, xmm6, 0
|
||||
shufps xmm7, xmm7, 0
|
||||
|
||||
// Load up the first row of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax]
|
||||
movaps xmm1, XMMWORD PTR [ecx]
|
||||
movaps xmm2, XMMWORD PTR [edx]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm5
|
||||
mulps xmm1, xmm6
|
||||
mulps xmm2, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi], xmm0
|
||||
|
||||
// Load up the second row of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax + 16]
|
||||
movaps xmm1, XMMWORD PTR [ecx + 16]
|
||||
movaps xmm2, XMMWORD PTR [edx + 16]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm5
|
||||
mulps xmm1, xmm6
|
||||
mulps xmm2, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi + 16], xmm0
|
||||
|
||||
// Load up the third row of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax + 32]
|
||||
movaps xmm1, XMMWORD PTR [ecx + 32]
|
||||
movaps xmm2, XMMWORD PTR [edx + 32]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm5
|
||||
mulps xmm1, xmm6
|
||||
mulps xmm2, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi + 32], xmm0
|
||||
}
|
||||
}
|
||||
return &scratchMatrix;
|
||||
|
||||
case 4:
|
||||
{
|
||||
matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
|
||||
matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
|
||||
matrix3x4_t &boneMat2 = pPoseToWorld[boneweights.bone[2]];
|
||||
matrix3x4_t &boneMat3 = pPoseToWorld[boneweights.bone[3]];
|
||||
float *pWeights = boneweights.weight;
|
||||
|
||||
_asm
|
||||
{
|
||||
mov eax, DWORD PTR [pWeights]
|
||||
movss xmm4, dword ptr[eax] ; boneweights.weight[0]
|
||||
movss xmm5, dword ptr[eax + 4] ; boneweights.weight[1]
|
||||
movss xmm6, dword ptr[eax + 8] ; boneweights.weight[2]
|
||||
movss xmm7, dword ptr[eax + 12] ; boneweights.weight[3]
|
||||
|
||||
mov eax, DWORD PTR [boneMat0]
|
||||
mov ecx, DWORD PTR [boneMat1]
|
||||
mov edx, DWORD PTR [boneMat2]
|
||||
mov esi, DWORD PTR [boneMat3]
|
||||
mov edi, DWORD PTR [scratchMatrix]
|
||||
|
||||
// Fill xmm5, 6, and 7 with all the bone weights
|
||||
shufps xmm4, xmm4, 0
|
||||
shufps xmm5, xmm5, 0
|
||||
shufps xmm6, xmm6, 0
|
||||
shufps xmm7, xmm7, 0
|
||||
|
||||
// Load up the first row of the four matrices
|
||||
movaps xmm0, XMMWORD PTR [eax]
|
||||
movaps xmm1, XMMWORD PTR [ecx]
|
||||
movaps xmm2, XMMWORD PTR [edx]
|
||||
movaps xmm3, XMMWORD PTR [esi]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm4
|
||||
mulps xmm1, xmm5
|
||||
mulps xmm2, xmm6
|
||||
mulps xmm3, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm2, xmm3
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi], xmm0
|
||||
|
||||
// Load up the second row of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax + 16]
|
||||
movaps xmm1, XMMWORD PTR [ecx + 16]
|
||||
movaps xmm2, XMMWORD PTR [edx + 16]
|
||||
movaps xmm3, XMMWORD PTR [esi + 16]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm4
|
||||
mulps xmm1, xmm5
|
||||
mulps xmm2, xmm6
|
||||
mulps xmm3, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm2, xmm3
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi + 16], xmm0
|
||||
|
||||
// Load up the third row of the three matrices
|
||||
movaps xmm0, XMMWORD PTR [eax + 32]
|
||||
movaps xmm1, XMMWORD PTR [ecx + 32]
|
||||
movaps xmm2, XMMWORD PTR [edx + 32]
|
||||
movaps xmm3, XMMWORD PTR [esi + 32]
|
||||
|
||||
// Multiply the rows by the weights
|
||||
mulps xmm0, xmm4
|
||||
mulps xmm1, xmm5
|
||||
mulps xmm2, xmm6
|
||||
mulps xmm3, xmm7
|
||||
|
||||
addps xmm0, xmm1
|
||||
addps xmm2, xmm3
|
||||
addps xmm0, xmm2
|
||||
movaps XMMWORD PTR [edi + 32], xmm0
|
||||
}
|
||||
}
|
||||
return &scratchMatrix;
|
||||
}
|
||||
#else
|
||||
#ifndef LINUX
|
||||
#pragma message( "ComputeSkinMatrixSSE C implementation only" )
|
||||
#endif
|
||||
extern matrix3x4_t *ComputeSkinMatrix( mstudioboneweight_t &boneweights, matrix3x4_t *pPoseToWorld, matrix3x4_t &scratchMatrix );
|
||||
return ComputeSkinMatrix( boneweights, pPoseToWorld, scratchMatrix );
|
||||
#endif
|
||||
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
static ConVar mat_tess_dump( "mat_tess_dump", "0", FCVAR_CHEAT );
|
||||
#endif
|
||||
|
||||
void CStudioRender::SkinSubDCage( mstudiovertex_t *pVertices, int nNumVertices,
|
||||
matrix3x4_t *pPoseToWorld, CCachedRenderData &vertexCache,
|
||||
unsigned short* pGroupToMesh, fltx4 *vOutput, bool bDoFlex )
|
||||
{
|
||||
VPROF_BUDGET( "CStudioRender::SkinSubDCage", _T("SubD Rendering") );
|
||||
|
||||
Vector *pSrcPos;
|
||||
ALIGN16 matrix3x4_t *pSkinMat, temp ALIGN16_POST;
|
||||
|
||||
Assert( nNumVertices > 0 );
|
||||
|
||||
for ( int j=0; j < nNumVertices; ++j )
|
||||
{
|
||||
mstudiovertex_t &vert = pVertices[pGroupToMesh[j]];
|
||||
|
||||
pSkinMat = ComputeSkinMatrixSSE( vert.m_BoneWeights, pPoseToWorld, temp );
|
||||
|
||||
if ( bDoFlex && vertexCache.IsVertexFlexed( pGroupToMesh[j] ) )
|
||||
{
|
||||
CachedPosNormTan_t* pFlexedVertex = vertexCache.GetFlexVertex( pGroupToMesh[j] );
|
||||
pSrcPos = &pFlexedVertex->m_Position.AsVector3D();
|
||||
|
||||
// Copy strange signed, 0..3 wrinkle tangent-flip encoding over to tangent.w
|
||||
pFlexedVertex->m_TangentS.w = pFlexedVertex->m_Position.w;
|
||||
}
|
||||
else // non-flexed case
|
||||
{
|
||||
pSrcPos = &vert.m_vecPosition;
|
||||
}
|
||||
|
||||
// Transform into world space
|
||||
Vector4DAligned vTemp;
|
||||
R_TransformVert( pSrcPos, pSkinMat, *(Vector4DAligned*)&vTemp );
|
||||
vOutput[j] = LoadAlignedSIMD( (float *) &vTemp );
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned short *InitializeTopologyIndexStruct( TopologyIndexStruct &quad, unsigned short *topologyIndex )
|
||||
{
|
||||
quad.vtx1RingSize = topologyIndex; topologyIndex += 4;
|
||||
quad.vtx1RingCenterQuadOffset = topologyIndex; topologyIndex += 4;
|
||||
quad.valences = topologyIndex; topologyIndex += 4;
|
||||
quad.minOneRingOffset = topologyIndex; topologyIndex += 4;
|
||||
quad.bndVtx = topologyIndex; topologyIndex += 4;
|
||||
quad.bndEdge = topologyIndex; topologyIndex += 4;
|
||||
quad.cornerVtx = topologyIndex; topologyIndex += 4;
|
||||
quad.loopGapAngle = topologyIndex; topologyIndex += 4;
|
||||
quad.nbCornerVtx = topologyIndex; topologyIndex += 4;
|
||||
quad.edgeBias = topologyIndex; topologyIndex += 8;
|
||||
quad.vUV0 = topologyIndex; topologyIndex += 4;
|
||||
quad.vUV1 = topologyIndex; topologyIndex += 4;
|
||||
quad.vUV2 = topologyIndex; topologyIndex += 4;
|
||||
quad.vUV3 = topologyIndex; topologyIndex += 4;
|
||||
quad.oneRing = topologyIndex;
|
||||
topologyIndex += quad.vtx1RingSize[0]+quad.vtx1RingSize[1]+quad.vtx1RingSize[2]+quad.vtx1RingSize[3];
|
||||
|
||||
return topologyIndex;
|
||||
}
|
||||
|
||||
static ConVar mat_tessellation_update_buffers( "mat_tessellation_update_buffers", "1", FCVAR_CHEAT );
|
||||
static ConVar mat_tessellation_cornertangents( "mat_tessellation_cornertangents", "1", FCVAR_CHEAT );
|
||||
static ConVar mat_tessellation_accgeometrytangents( "mat_tessellation_accgeometrytangents", "0", FCVAR_CHEAT );
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
bool NotQuiteEqual( Vector4D &vA, Vector4D &vB )
|
||||
{
|
||||
float flEpsilon = 0.05f;
|
||||
Vector4D vDelta = vA - vB;
|
||||
float flDist = sqrt( vDelta.x * vDelta.x + vDelta.y * vDelta.y + vDelta.z * vDelta.z );
|
||||
bool bSameVector = ( vA.x == vB.x ) && ( vA.y == vB.y ) && ( vA.z == vB.z );
|
||||
|
||||
return ( flDist < flEpsilon ) && !bSameVector;
|
||||
}
|
||||
|
||||
void DumpDebugPositions()
|
||||
{
|
||||
|
||||
for ( int i=0; i< g_DebugCornerPositions.Count(); i++ )
|
||||
{
|
||||
bool bCrack = false;
|
||||
for ( int j=0; j< g_DebugCornerPositions.Count(); j++ )
|
||||
{
|
||||
if ( NotQuiteEqual( g_DebugCornerPositions[i], g_DebugCornerPositions[j] ) )
|
||||
{
|
||||
bCrack = true;
|
||||
Assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
DevMsg( "%s C - %.15f, %.15f, %.15f\n", bCrack ? "*** " : " ", g_DebugCornerPositions[i].x, g_DebugCornerPositions[i].y, g_DebugCornerPositions[i].z );
|
||||
}
|
||||
|
||||
for ( int i=0; i< g_DebugEdgePositions.Count(); i++ )
|
||||
{
|
||||
bool bCrack = false;
|
||||
for ( int j=0; j< g_DebugEdgePositions.Count(); j++ )
|
||||
{
|
||||
if ( NotQuiteEqual( g_DebugEdgePositions[i], g_DebugEdgePositions[j] ) )
|
||||
{
|
||||
bCrack = true;
|
||||
}
|
||||
}
|
||||
|
||||
DevMsg( "%s E - %.15f, %.15f, %.15f\n", bCrack ? "*** " : " ", g_DebugEdgePositions[i].x, g_DebugEdgePositions[i].y, g_DebugEdgePositions[i].z );
|
||||
}
|
||||
|
||||
for ( int i=0; i< g_DebugInteriorPositions.Count(); i++ )
|
||||
{
|
||||
bool bCrack = false;
|
||||
for ( int j=0; j< g_DebugInteriorPositions.Count(); j++ )
|
||||
{
|
||||
if ( NotQuiteEqual( g_DebugInteriorPositions[i], g_DebugInteriorPositions[j] ) )
|
||||
{
|
||||
bCrack = true;
|
||||
}
|
||||
}
|
||||
|
||||
DevMsg( "%s I - %.15f, %.15f, %.15f\n", bCrack ? "*** " : " ", g_DebugInteriorPositions[i].x, g_DebugInteriorPositions[i].y, g_DebugInteriorPositions[i].z );
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _DEBUG
|
||||
|
||||
void GenerateWorldSpacePatches( float *pSubDBuff, int nNumPatches, unsigned short *pTopologyIndices, fltx4 *pWSVertices, bool bRegularPatch )
|
||||
{
|
||||
VPROF_BUDGET( "CStudioRender::GenerateWorldSpacePatches", _T("SubD Rendering") );
|
||||
|
||||
TopologyIndexStruct quad;
|
||||
unsigned short *nextPatchIndices = InitializeTopologyIndexStruct( quad, pTopologyIndices );
|
||||
|
||||
set_ShowACCGeometryTangents(mat_tessellation_accgeometrytangents.GetBool());
|
||||
set_UseCornerTangents(mat_tessellation_cornertangents.GetBool());
|
||||
|
||||
ALIGN16 Vector4D Geo[16] ALIGN16_POST;
|
||||
ALIGN16 Vector4D TanU[12] ALIGN16_POST;
|
||||
ALIGN16 Vector4D TanV[12] ALIGN16_POST;
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( mat_tess_dump.GetBool() )
|
||||
{
|
||||
// Debug Arrays
|
||||
g_DebugCornerPositions.EnsureCapacity( nNumPatches * 4 );
|
||||
g_DebugEdgePositions.EnsureCapacity( nNumPatches * 8 );
|
||||
g_DebugInteriorPositions.EnsureCapacity( nNumPatches * 4 );
|
||||
|
||||
// Empty the arrays this time around
|
||||
g_DebugCornerPositions.RemoveAll();
|
||||
g_DebugEdgePositions.RemoveAll();
|
||||
g_DebugInteriorPositions.RemoveAll();
|
||||
}
|
||||
#endif
|
||||
|
||||
for( int p = 0; p < nNumPatches; p++ )
|
||||
{
|
||||
#if defined( USE_OPT )
|
||||
ComputeACCAllPatches( pWSVertices, &quad, Geo, TanU, TanV, bRegularPatch );
|
||||
#else
|
||||
ComputeACCGeometryPatch( pWSVertices, &quad, Geo );
|
||||
ComputeACCTangentPatches( pWSVertices, &quad, Geo, TanU, TanV );
|
||||
#endif
|
||||
|
||||
for ( int i=0; i < 16; i++ )
|
||||
{
|
||||
pSubDBuff[ i * 3 + 0 ] = Geo[i].x;
|
||||
pSubDBuff[ i * 3 + 1 ] = Geo[i].y;
|
||||
pSubDBuff[ i * 3 + 2 ] = Geo[i].z;
|
||||
|
||||
}
|
||||
|
||||
for ( int i=0; i<12; i++ )
|
||||
{
|
||||
pSubDBuff[ i * 3 + 0 + 48 ] = TanU[ i ].x;
|
||||
pSubDBuff[ i * 3 + 1 + 48 ] = TanU[ i ].y;
|
||||
pSubDBuff[ i * 3 + 2 + 48 ] = TanU[ i ].z;
|
||||
}
|
||||
|
||||
for ( int i=0; i<12; i++ )
|
||||
{
|
||||
pSubDBuff[ i * 3 + 0 + 84 ] = TanV[ i ].x;
|
||||
pSubDBuff[ i * 3 + 1 + 84 ] = TanV[ i ].y;
|
||||
pSubDBuff[ i * 3 + 2 + 84 ] = TanV[ i ].z;
|
||||
}
|
||||
|
||||
pSubDBuff += 120; // 30 * sizeof( float )
|
||||
|
||||
nextPatchIndices = InitializeTopologyIndexStruct( quad, nextPatchIndices );
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if ( mat_tess_dump.GetBool() )
|
||||
{
|
||||
// These should be a particular size
|
||||
Assert( g_DebugCornerPositions.Count() == ( nNumPatches * 4 ) );
|
||||
Assert( g_DebugEdgePositions.Count() == ( nNumPatches * 8 ) );
|
||||
Assert( g_DebugInteriorPositions.Count() == ( nNumPatches * 4 ) );
|
||||
|
||||
DumpDebugPositions();
|
||||
mat_tess_dump.SetValue( 0 ); // Turn back off
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------
|
||||
// Top level function for mapping a quad mesh to an array of Bicubic Bezier patches
|
||||
//-----------------------------------------------------------------------------------
|
||||
void CStudioRender::GenerateBicubicPatches( mstudiomesh_t* pmesh, studiomeshgroup_t* pGroup, bool bDoFlex )
|
||||
{
|
||||
#if defined( LINUX )
|
||||
Assert(0);
|
||||
#else
|
||||
VPROF_BUDGET( "CStudioRender::GenerateBicubicPatches", _T("SubD Rendering") );
|
||||
|
||||
FillTables(); // This only does work the first time through
|
||||
|
||||
Assert( pmesh );
|
||||
Assert( pGroup );
|
||||
|
||||
const mstudio_meshvertexdata_t *vertData = pmesh->GetVertexData( m_pStudioHdr );
|
||||
Assert( vertData );
|
||||
|
||||
mstudiovertex_t *pVertices = vertData->Vertex( 0 );
|
||||
|
||||
m_vSkinnedSubDVertices.SetCount( pGroup->m_NumVertices );
|
||||
|
||||
// First, apply software flexing and skinning to the vertices
|
||||
SkinSubDCage( pVertices, pGroup->m_NumVertices, m_PoseToWorld,
|
||||
m_VertexCache, pGroup->m_pGroupIndexToMeshIndex, m_vSkinnedSubDVertices.Base(), bDoFlex );
|
||||
|
||||
// Early out
|
||||
if ( mat_tessellation_update_buffers.GetBool() == false )
|
||||
return;
|
||||
|
||||
// Lock the subd buffers
|
||||
int nNumPatches = 0;
|
||||
for ( int s=0; s<pGroup->m_NumStrips; ++s )
|
||||
{
|
||||
nNumPatches += pGroup->m_pUniqueFaces[s];
|
||||
}
|
||||
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
float *pSubDBuff = pRenderContext->LockSubDBuffer( nNumPatches );
|
||||
|
||||
// Now we are in world space, we can map to array of Bicubic patches
|
||||
int totalIndices = 0;
|
||||
float *pCurrentPtr = pSubDBuff;
|
||||
for ( int s=0; s<pGroup->m_NumStrips; ++s )
|
||||
{
|
||||
OptimizedModel::StripHeader_t *pStrip = &pGroup->m_pStripData[s];
|
||||
int StripFaces = pGroup->m_pUniqueFaces[s];
|
||||
|
||||
GenerateWorldSpacePatches( pCurrentPtr, StripFaces, &pGroup->m_pTopologyIndices[totalIndices], m_vSkinnedSubDVertices.Base(), ( pStrip->flags & OptimizedModel::STRIP_IS_QUADLIST_REG ) != 0 );
|
||||
|
||||
totalIndices += pStrip->numTopologyIndices;
|
||||
pCurrentPtr += StripFaces * 120;
|
||||
}
|
||||
|
||||
// Unlock subd buffers
|
||||
pRenderContext->UnlockSubDBuffer( );
|
||||
|
||||
#endif // !LINUX
|
||||
}
|
||||
|
||||
|
||||
// Transform Tangent vector
|
||||
static void R_TransformTangent( const Vector4D *pSrcTangentS, matrix3x4_t *pSkinMat, Vector4DAligned &tangentS )
|
||||
{
|
||||
VPROF_BUDGET( "R_TransformTangent", _T("SubD Rendering") );
|
||||
|
||||
tangentS.x = pSrcTangentS->x * (*pSkinMat)[0][0] + pSrcTangentS->y * (*pSkinMat)[0][1] + pSrcTangentS->z * (*pSkinMat)[0][2];
|
||||
tangentS.y = pSrcTangentS->x * (*pSkinMat)[1][0] + pSrcTangentS->y * (*pSkinMat)[1][1] + pSrcTangentS->z * (*pSkinMat)[1][2];
|
||||
tangentS.z = pSrcTangentS->x * (*pSkinMat)[2][0] + pSrcTangentS->y * (*pSkinMat)[2][1] + pSrcTangentS->z * (*pSkinMat)[2][2];
|
||||
tangentS.w = pSrcTangentS->w;
|
||||
}
|
||||
|
||||
// Transforms per-vertex tangent vector, copies texture coordinates etc into dynamic VB
|
||||
void CStudioRender::SoftwareProcessQuadMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
|
||||
int numFaces, unsigned short* pGroupToMesh,
|
||||
unsigned short *pTopologyIndices, bool bTangentSpace, bool bDoFlex )
|
||||
{
|
||||
VPROF_BUDGET( "CStudioRender::SoftwareProcessQuadMesh", _T("SubD Rendering") );
|
||||
|
||||
Vector4D *pStudioTangentS = NULL;
|
||||
|
||||
ALIGN16 QuadTessVertex_t quadVertex ALIGN16_POST;
|
||||
|
||||
// QuadTessVertex_t currently has the following map:
|
||||
// +-----------------------------------+
|
||||
// | tanX | tanY | tanZ | sBWrnk | <- Tangent in .xyz, Binormal sign flip bit plus wrinkle in .w
|
||||
// +-----------------------------------+
|
||||
// | tcU0 | tcV0 | tcU1 | tcV1 | <- Interior TC, Parametric V Edge TC
|
||||
// +-----------------------------------+
|
||||
// | tcU2 | tcV2 | tcU3 | tcV3 | <- Parametric U Edge TC, Corner TC
|
||||
// +-----------------------------------+
|
||||
|
||||
quadVertex.m_vTangent.Init( 1.0f, 0.0f, 0.0f, 1.0f );
|
||||
|
||||
ALIGN16 matrix3x4_t *pSkinMat, matTemp ALIGN16_POST;
|
||||
|
||||
Assert( numFaces > 0 );
|
||||
|
||||
const mstudio_meshvertexdata_t *pVertData = pmesh->GetVertexData( m_pStudioHdr );
|
||||
Assert( pVertData );
|
||||
if ( !pVertData )
|
||||
return;
|
||||
|
||||
mstudiovertex_t *pVertices = pVertData->Vertex( 0 );
|
||||
|
||||
|
||||
if ( bTangentSpace )
|
||||
{
|
||||
pStudioTangentS = pVertData->TangentS( 0 );
|
||||
}
|
||||
|
||||
TopologyIndexStruct quad;
|
||||
unsigned short *nextPatchIndices = InitializeTopologyIndexStruct( quad, pTopologyIndices );
|
||||
|
||||
for ( int i=0; i < numFaces; ++i ) // Run over faces
|
||||
{
|
||||
int patchCorner = 0;
|
||||
|
||||
#if 0
|
||||
Vector4D debugTangent[4];
|
||||
for ( int j=0; j < 4; ++j )
|
||||
{
|
||||
int idx = quad.oneRing[patchCorner];
|
||||
memcpy( &debugTangent[j], &pStudioTangentS[idx], sizeof( Vector4D ) );
|
||||
patchCorner += quad.vtx1RingSize[j];
|
||||
}
|
||||
|
||||
// These should be the same sign for a given patch.
|
||||
// If they're not, that's bad
|
||||
Assert( ( debugTangent[0].w == debugTangent[1].w ) &&
|
||||
( debugTangent[1].w == debugTangent[2].w ) &&
|
||||
( debugTangent[2].w == debugTangent[3].w ) );
|
||||
|
||||
patchCorner = 0;
|
||||
#endif
|
||||
|
||||
for ( int j=0; j < 4; ++j ) // Four verts per face
|
||||
{
|
||||
int idx = quad.oneRing[patchCorner];
|
||||
mstudiovertex_t &vert = pVertices[idx];
|
||||
|
||||
if ( bTangentSpace )
|
||||
{
|
||||
pSkinMat = ComputeSkinMatrixSSE( vert.m_BoneWeights, m_PoseToWorld, matTemp );
|
||||
|
||||
if ( bDoFlex && m_VertexCache.IsVertexFlexed( idx ) )
|
||||
{
|
||||
CachedPosNormTan_t* pFlexedVertex = m_VertexCache.GetFlexVertex( idx );
|
||||
R_TransformTangent( &(pFlexedVertex->m_TangentS), pSkinMat, *(Vector4DAligned*)&quadVertex.m_vTangent );
|
||||
}
|
||||
else // non-flexed case
|
||||
{
|
||||
R_TransformTangent( &pStudioTangentS[idx], pSkinMat, *(Vector4DAligned*)&quadVertex.m_vTangent );
|
||||
quadVertex.m_vTangent.w *= 2; // non-flexed vertex should have wrinkle of -2 or +2
|
||||
}
|
||||
}
|
||||
|
||||
// Store 4 texcoords per quad corner
|
||||
quadVertex.m_vUV01.x = pVertices[ quad.vUV0[j] ].m_vecTexCoord.x;
|
||||
quadVertex.m_vUV01.y = pVertices[ quad.vUV0[j] ].m_vecTexCoord.y;
|
||||
quadVertex.m_vUV01.z = pVertices[ quad.vUV1[j] ].m_vecTexCoord.x;
|
||||
quadVertex.m_vUV01.w = pVertices[ quad.vUV1[j] ].m_vecTexCoord.y;
|
||||
quadVertex.m_vUV23.x = pVertices[ quad.vUV2[j] ].m_vecTexCoord.x;
|
||||
quadVertex.m_vUV23.y = pVertices[ quad.vUV2[j] ].m_vecTexCoord.y;
|
||||
quadVertex.m_vUV23.z = pVertices[ quad.vUV3[j] ].m_vecTexCoord.x;
|
||||
quadVertex.m_vUV23.w = pVertices[ quad.vUV3[j] ].m_vecTexCoord.y;
|
||||
|
||||
meshBuilder.FastQuadVertexSSE( quadVertex );
|
||||
|
||||
patchCorner += quad.vtx1RingSize[j];
|
||||
}
|
||||
|
||||
nextPatchIndices = InitializeTopologyIndexStruct( quad, nextPatchIndices );
|
||||
}
|
||||
|
||||
meshBuilder.FastAdvanceNVertices( numFaces * 4 );
|
||||
}
|
||||
1535
studiorender/r_studiosubd_patches.cpp
Normal file
1535
studiorender/r_studiosubd_patches.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
studiorender/r_studiosubd_patches.h
Normal file
70
studiorender/r_studiosubd_patches.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef R_STUDIOSUBD_PATCHES_H
|
||||
#define R_STUDIOSUBD_PATCHES_H
|
||||
|
||||
// Maximum valence we expect to encounter for extraordinary vertices
|
||||
#define MAX_VALENCE 19
|
||||
|
||||
#define CORNER_WITH_SMOOTHBNDTANGENTS 2
|
||||
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "mathlib/vector4d.h"
|
||||
#include "mathlib/ssemath.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
#define ALIGN(n) __declspec( align( n ) )
|
||||
|
||||
// Undef this to use the unoptimized conversion routines
|
||||
#define USE_OPT
|
||||
|
||||
// Uncomment this to separate computation between regular patches and extraordinary patches
|
||||
#define SEPARATE_REGULAR_AND_EXTRA
|
||||
|
||||
// Uncomment this to disable tangent patch computation
|
||||
//#define NO_TANGENTS
|
||||
|
||||
// if you change this make sure to adjust NUM_TOPOLOGY_INDICES_ATTRIBUTES in studiorendercontext.cpp as well!
|
||||
struct TopologyIndexStruct
|
||||
{
|
||||
unsigned short *vtx1RingSize;
|
||||
unsigned short *vtx1RingCenterQuadOffset;
|
||||
|
||||
unsigned short *valences;
|
||||
unsigned short *minOneRingOffset;
|
||||
|
||||
unsigned short *bndVtx;
|
||||
unsigned short *bndEdge;
|
||||
unsigned short *cornerVtx;
|
||||
|
||||
unsigned short *loopGapAngle;
|
||||
|
||||
unsigned short *edgeBias;
|
||||
|
||||
unsigned short *nbCornerVtx;
|
||||
|
||||
unsigned short *oneRing;
|
||||
|
||||
unsigned short *vUV0;
|
||||
unsigned short *vUV1;
|
||||
unsigned short *vUV2;
|
||||
unsigned short *vUV3;
|
||||
};
|
||||
|
||||
void set_ShowACCGeometryTangents(bool v);
|
||||
void set_CornerCorrection(bool v);
|
||||
void set_UseCornerTangents(bool v);
|
||||
|
||||
void FillTables(); // fill patch stencil buffers
|
||||
|
||||
// compute patch control points
|
||||
#if defined( USE_OPT )
|
||||
void ComputeACCAllPatches( fltx4* pWSVertices, TopologyIndexStruct* quad, Vector4D* Pos, Vector4D* TanU, Vector4D* TanV, bool bRegularPatch = false );
|
||||
#else
|
||||
void ComputeACCGeometryPatch( Vector4D* pWSVertices, TopologyIndexStruct *quad, Vector4D* Pos);
|
||||
void ComputeACCTangentPatches( Vector4D* pWSVertices, TopologyIndexStruct* quad, Vector4D* Pos, Vector4D* TanU, Vector4D* TanV );
|
||||
#endif
|
||||
|
||||
void EvaluateACC(unsigned short nPoints, Vector2D *UVs, Vector4D *cpP, Vector4D *cpU, Vector4D *cpV, Vector4D *pos, Vector *nor, Vector2D *uv, Vector4D *tanU, Vector4D *tanV );
|
||||
void EvaluateGregory(unsigned short nPoints, Vector2D *UVs, Vector4D *cpP, Vector4D *pos, Vector *nor, Vector2D *uv, Vector4D *tanU, Vector4D *tanV );
|
||||
|
||||
|
||||
#endif //R_STUDIOSUBD_PATCHES_H
|
||||
2710
studiorender/studiorender.cpp
Normal file
2710
studiorender/studiorender.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1048
studiorender/studiorender.h
Normal file
1048
studiorender/studiorender.h
Normal file
File diff suppressed because it is too large
Load Diff
118
studiorender/studiorender.vpc
Normal file
118
studiorender/studiorender.vpc
Normal file
@@ -0,0 +1,118 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// STUDIORENDER.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$macro SRCDIR ".."
|
||||
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
|
||||
|
||||
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Linker
|
||||
{
|
||||
$SystemLibraries "iconv" [$OSXALL]
|
||||
}
|
||||
|
||||
$Compiler
|
||||
{
|
||||
$PreprocessorDefinitions "$BASE;STUDIORENDER_EXPORTS;PROTECTED_THINGS_ENABLE"
|
||||
}
|
||||
|
||||
$Compiler [$PS3]
|
||||
{
|
||||
$AdditionalOptions "$BASE --pending_instantiations=256"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "studiorender"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "studiorender.cpp"
|
||||
$File "studiorendercontext.cpp"
|
||||
$File "flexrenderdata.cpp"
|
||||
$File "r_studio.cpp"
|
||||
$File "r_studiodecal.cpp"
|
||||
$File "r_studiodraw.cpp"
|
||||
$File "r_studiodraw_computeflexedvertex.cpp"
|
||||
$File "r_studioflex.cpp"
|
||||
$File "r_studiosubd.cpp"
|
||||
$File "r_studiosubd_patches.cpp"
|
||||
$File "r_studiogettriangles.cpp"
|
||||
$File "r_studiolight.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "r_studiolight.h"
|
||||
$File "r_studiosubd_patches.h"
|
||||
$File "studiorender.h"
|
||||
$File "studiorendercontext.h"
|
||||
$File "flexrenderdata.h"
|
||||
}
|
||||
|
||||
$Folder "Public Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\basehandle.h"
|
||||
$File "$SRCDIR\public\tier0\basetypes.h"
|
||||
$File "$SRCDIR\public\bspflags.h"
|
||||
$File "$SRCDIR\public\clientstats.h"
|
||||
$File "$SRCDIR\public\cmodel.h"
|
||||
$File "$SRCDIR\public\mathlib\compressed_vector.h"
|
||||
$File "$SRCDIR\public\const.h"
|
||||
$File "$SRCDIR\public\tier1\convar.h"
|
||||
$File "$SRCDIR\public\tier0\dbg.h"
|
||||
$File "$SRCDIR\public\tier0\fasttimer.h"
|
||||
$File "$SRCDIR\public\gametrace.h"
|
||||
$File "$SRCDIR\public\appframework\iappsystem.h"
|
||||
$File "$SRCDIR\public\tier0\icommandline.h"
|
||||
$File "$SRCDIR\public\ihandleentity.h"
|
||||
$File "$SRCDIR\public\materialsystem\imaterial.h"
|
||||
$File "$SRCDIR\public\materialsystem\imaterialsystem.h"
|
||||
$File "$SRCDIR\public\materialsystem\imaterialsystemhardwareconfig.h"
|
||||
$File "$SRCDIR\public\materialsystem\imaterialvar.h"
|
||||
$File "$SRCDIR\public\materialsystem\imesh.h"
|
||||
$File "$SRCDIR\public\tier1\interface.h"
|
||||
$File "$SRCDIR\public\istudiorender.h"
|
||||
$File "$SRCDIR\public\materialsystem\itexture.h"
|
||||
$File "$SRCDIR\public\mathlib\mathlib.h"
|
||||
$File "$SRCDIR\public\measure_section.h"
|
||||
$File "$SRCDIR\public\tier0\mem.h"
|
||||
$File "$SRCDIR\public\tier0\memalloc.h"
|
||||
$File "$SRCDIR\public\tier0\memdbgoff.h"
|
||||
$File "$SRCDIR\public\tier0\memdbgon.h"
|
||||
$File "$SRCDIR\public\model_types.h"
|
||||
$File "$SRCDIR\public\optimize.h"
|
||||
$File "$SRCDIR\public\pixelwriter.h"
|
||||
$File "$SRCDIR\public\tier0\platform.h"
|
||||
$File "$SRCDIR\public\string_t.h"
|
||||
$File "$SRCDIR\public\tier1\strtools.h"
|
||||
$File "$SRCDIR\public\studio.h"
|
||||
$File "$SRCDIR\public\tier1\utlbuffer.h"
|
||||
$File "$SRCDIR\public\tier1\utllinkedlist.h"
|
||||
$File "$SRCDIR\public\tier1\utlmemory.h"
|
||||
$File "$SRCDIR\public\tier1\utlvector.h"
|
||||
$File "$SRCDIR\public\vcollide.h"
|
||||
$File "$SRCDIR\public\mathlib\vector.h"
|
||||
$File "$SRCDIR\public\mathlib\vector2d.h"
|
||||
$File "$SRCDIR\public\mathlib\vector4d.h"
|
||||
$File "$SRCDIR\public\mathlib\vmatrix.h"
|
||||
$File "$SRCDIR\public\mathlib\vplane.h"
|
||||
$File "$SRCDIR\public\tier0\vprof.h"
|
||||
$File "$SRCDIR\public\vstdlib\vstdlib.h"
|
||||
$File "$SRCDIR\public\vtf\vtf.h"
|
||||
$File "$SRCDIR\public\tier1\UtlStringMap.h"
|
||||
}
|
||||
|
||||
$folder "Link Libraries"
|
||||
{
|
||||
$Implib "$LIBPUBLIC\vstdlib"
|
||||
$Lib bitmap
|
||||
$Lib mathlib
|
||||
$Lib tier2
|
||||
$Lib tier3
|
||||
}
|
||||
}
|
||||
13
studiorender/studiorender.vpc.vpc_cache
Normal file
13
studiorender/studiorender.vpc.vpc_cache
Normal file
@@ -0,0 +1,13 @@
|
||||
"vpc_cache"
|
||||
{
|
||||
"CacheVersion" "1"
|
||||
"win32"
|
||||
{
|
||||
"CRCFile" "studiorender.vcxproj.vpc_crc"
|
||||
"OutputFiles"
|
||||
{
|
||||
"0" "studiorender.vcxproj"
|
||||
"1" "studiorender.vcxproj.filters"
|
||||
}
|
||||
}
|
||||
}
|
||||
2826
studiorender/studiorendercontext.cpp
Normal file
2826
studiorender/studiorendercontext.cpp
Normal file
File diff suppressed because it is too large
Load Diff
247
studiorender/studiorendercontext.h
Normal file
247
studiorender/studiorendercontext.h
Normal file
@@ -0,0 +1,247 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef STUDIORENDERCONTEXT_H
|
||||
#define STUDIORENDERCONTEXT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "istudiorender.h"
|
||||
#include "tier3/tier3.h"
|
||||
#include "studio.h"
|
||||
#include "tier1/delegates.h"
|
||||
#include "tier1/memstack.h"
|
||||
#include "studiorender.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Foward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class IStudioDataCache;
|
||||
class CStudioRender;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Global interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
extern IStudioDataCache *g_pStudioDataCache;
|
||||
extern CStudioRender *g_pStudioRenderImp;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal config structure
|
||||
//-----------------------------------------------------------------------------
|
||||
struct StudioRenderConfigInternal_t : public StudioRenderConfig_t
|
||||
{
|
||||
bool m_bSupportsVertexAndPixelShaders : 1;
|
||||
bool m_bSupportsOverbright : 1;
|
||||
bool m_bEnableHWMorph : 1;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// All the data needed to render a studiomodel
|
||||
//-----------------------------------------------------------------------------
|
||||
struct FlexWeights_t
|
||||
{
|
||||
float *m_pFlexWeights;
|
||||
float *m_pFlexDelayedWeights;
|
||||
};
|
||||
|
||||
struct StudioRenderContext_t
|
||||
{
|
||||
StudioRenderConfigInternal_t m_Config;
|
||||
Vector m_ViewTarget;
|
||||
Vector m_ViewOrigin;
|
||||
Vector m_ViewRight;
|
||||
Vector m_ViewUp;
|
||||
Vector m_ViewPlaneNormal;
|
||||
Vector4D m_LightBoxColors[6];
|
||||
LightDesc_t m_LocalLights[MAXLOCALLIGHTS];
|
||||
int m_NumLocalLights;
|
||||
float m_ColorMod[3];
|
||||
float m_AlphaMod;
|
||||
IMaterial* m_pForcedMaterial[MAX_MAT_OVERRIDES];
|
||||
OverrideType_t m_nForcedMaterialType;
|
||||
int m_nForcedMaterialIndex[MAX_MAT_OVERRIDES];
|
||||
int m_nForcedMaterialIndexCount;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper to queue up calls if necessary
|
||||
//-----------------------------------------------------------------------------
|
||||
#define QUEUE_STUDIORENDER_CALL( FuncName, ClassName, pObject, ... ) \
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); \
|
||||
ICallQueue *pCallQueue = pRenderContext->GetCallQueue(); \
|
||||
if ( !pCallQueue || studio_queue_mode.GetInt() == 0 ) \
|
||||
{ \
|
||||
pObject->FuncName( __VA_ARGS__ ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pCallQueue->QueueCall( pObject, &ClassName::FuncName, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
#define QUEUE_STUDIORENDER_CALL_RC( FuncName, ClassName, pObject, pRenderContext, ... ) \
|
||||
ICallQueue *pCallQueue = pRenderContext->GetCallQueue(); \
|
||||
if ( !pCallQueue || studio_queue_mode.GetInt() == 0 ) \
|
||||
{ \
|
||||
pObject->FuncName( __VA_ARGS__ ); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
pCallQueue->QueueCall( pObject, &ClassName::FuncName, ##__VA_ARGS__ ); \
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Implementation of IStudioRender
|
||||
//-----------------------------------------------------------------------------
|
||||
class CStudioRenderContext : public CTier3AppSystem< IStudioRender >
|
||||
{
|
||||
typedef CTier3AppSystem< IStudioRender > BaseClass;
|
||||
|
||||
// Methods of IAppSystem
|
||||
public:
|
||||
virtual bool Connect( CreateInterfaceFn factory );
|
||||
virtual void Disconnect();
|
||||
virtual void *QueryInterface( const char *pInterfaceName );
|
||||
virtual InitReturnVal_t Init();
|
||||
virtual void Shutdown();
|
||||
|
||||
// Methods of IStudioRender
|
||||
public:
|
||||
virtual void BeginFrame( void );
|
||||
virtual void EndFrame( void );
|
||||
virtual void Mat_Stub( IMaterialSystem *pMatSys );
|
||||
virtual void UpdateConfig( const StudioRenderConfig_t& config );
|
||||
virtual void GetCurrentConfig( StudioRenderConfig_t& config );
|
||||
virtual bool LoadModel(studiohdr_t *pStudioHdr, void *pVtxData, studiohwdata_t *pHardwareData);
|
||||
virtual void UnloadModel( studiohwdata_t *pHardwareData );
|
||||
virtual void RefreshStudioHdr( studiohdr_t* pStudioHdr, studiohwdata_t* pHardwareData );
|
||||
virtual void SetEyeViewTarget( const studiohdr_t *pStudioHdr, int nBodyIndex, const Vector& worldPosition );
|
||||
virtual void SetAmbientLightColors( const Vector *pAmbientOnlyColors );
|
||||
virtual void SetAmbientLightColors( const Vector4D *pAmbientOnlyColors );
|
||||
virtual void SetLocalLights( int numLights, const LightDesc_t *pLights );
|
||||
virtual int GetNumAmbientLightSamples();
|
||||
virtual const Vector *GetAmbientLightDirections();
|
||||
virtual void SetViewState( const Vector& viewOrigin, const Vector& viewRight, const Vector& viewUp, const Vector& viewPlaneNormal );
|
||||
virtual int GetNumLODs( const studiohwdata_t &hardwareData ) const;
|
||||
virtual float GetLODSwitchValue( const studiohwdata_t &hardwareData, int lod ) const;
|
||||
virtual void SetLODSwitchValue( studiohwdata_t &hardwareData, int lod, float switchValue );
|
||||
virtual void SetColorModulation( const float* pColor );
|
||||
virtual void SetAlphaModulation( float alpha );
|
||||
virtual void DrawModel( DrawModelResults_t *pResults, const DrawModelInfo_t& info, matrix3x4_t *pCustomBoneToWorld, float *pFlexWeights, float *pFlexDelayedWeights, const Vector& origin, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
|
||||
virtual void DrawModelArray( const StudioModelArrayInfo_t &drawInfo, int arrayCount, StudioArrayInstanceData_t *pInstanceData, int instanceStride, int flags );
|
||||
virtual void DrawModelArray( const StudioModelArrayInfo2_t &drawInfo, int nArrayCount, StudioArrayData_t *pArrayData, int nInstanceStride, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
|
||||
virtual void DrawModelShadowArray( int nCount, StudioArrayData_t *pShadowData, int nInstanceStride, int flags );
|
||||
virtual void DrawModelStaticProp( const DrawModelInfo_t& info, const matrix3x4_t &modelToWorld, int flags = STUDIORENDER_DRAW_ENTIRE_MODEL );
|
||||
virtual void DrawModelArrayStaticProp( const DrawModelInfo_t& info, int nInstanceCount, const MeshInstanceData_t *pInstanceData, ColorMeshInfo_t **pColorMeshes );
|
||||
virtual void DrawStaticPropDecals( const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld );
|
||||
virtual void DrawStaticPropShadows( const DrawModelInfo_t &drawInfo, const matrix3x4_t &modelToWorld, int flags );
|
||||
virtual void ForcedMaterialOverride( IMaterial *newMaterial, OverrideType_t nOverrideType = OVERRIDE_NORMAL, int nMaterialIndex = -1 );
|
||||
virtual bool IsForcedMaterialOverride();
|
||||
DELEGATE_TO_OBJECT_1( StudioDecalHandle_t, CreateDecalList, studiohwdata_t *, g_pStudioRenderImp );
|
||||
virtual void DestroyDecalList( StudioDecalHandle_t handle );
|
||||
virtual void AddDecal( StudioDecalHandle_t handle, studiohdr_t *pStudioHdr, matrix3x4_t *pBoneToWorld, const Ray_t & ray, const Vector& decalUp, IMaterial* pDecalMaterial, float radius, int body, bool noPokethru, int maxLODToDecal = ADDDECAL_TO_ALL_LODS, void *pvProxyUserData = NULL, int nAdditionalDecalFlags = 0 );
|
||||
virtual void ComputeLighting( const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting );
|
||||
virtual void ComputeLightingConstDirectional( const Vector* pAmbient, int lightCount, LightDesc_t* pLights, const Vector& pt, const Vector& normal, Vector& lighting, float flDirectionalAmount );
|
||||
virtual void AddShadow( IMaterial* pMaterial, void* pProxyData, FlashlightState_t *pFlashlightState, VMatrix *pWorldToTexture, ITexture *pFlashlightDepthTexture );
|
||||
virtual void ClearAllShadows();
|
||||
virtual int ComputeModelLod( studiohwdata_t* pHardwareData, float flUnitSphereSize, float *pMetric = NULL );
|
||||
virtual void GetPerfStats( DrawModelResults_t *pResults, const DrawModelInfo_t &info, CUtlBuffer *pSpewBuf = NULL ) const;
|
||||
virtual void GetTriangles( const DrawModelInfo_t& info, matrix3x4_t *pBoneToWorld, GetTriangles_Output_t &out );
|
||||
virtual int GetMaterialList( studiohdr_t *pStudioHdr, int count, IMaterial** ppMaterials );
|
||||
virtual int GetMaterialListFromBodyAndSkin( MDLHandle_t studio, int nSkin, int nBody, int nCountOutputMaterials, IMaterial** ppOutputMaterials );
|
||||
|
||||
#ifndef _CERT
|
||||
// Gathers information about faces rendered this past frame and feeds them into the given callback function (presuambly to spew)
|
||||
// Callback may be invoked on mat queue thread!
|
||||
virtual void GatherRenderedFaceInfo( IStudioRender::FaceInfoCallbackFunc_t pFunc );
|
||||
#endif // _CERT
|
||||
|
||||
// Other public methods
|
||||
public:
|
||||
CStudioRenderContext();
|
||||
virtual ~CStudioRenderContext();
|
||||
|
||||
private:
|
||||
// Load, unload materials
|
||||
void LoadMaterials( studiohdr_t *phdr, OptimizedModel::FileHeader_t *, studioloddata_t &lodData, int lodID );
|
||||
|
||||
// Determines material flags
|
||||
void ComputeMaterialFlags( studiohdr_t *phdr, IMaterial *pMaterial );
|
||||
|
||||
// Creates, destroys static meshes
|
||||
void R_StudioCreateStaticMeshes( studiohdr_t *pStudioHdr, OptimizedModel::FileHeader_t* pVtxHdr,
|
||||
studiohwdata_t *pStudioHWData, int lodID, int *pColorMeshID );
|
||||
void R_StudioCreateSingleMesh( studiohdr_t *pStudioHdr, studioloddata_t *pStudioLodData,
|
||||
mstudiomesh_t* pMesh, OptimizedModel::MeshHeader_t* pVtxMesh, int numBones,
|
||||
studiomeshdata_t* pMeshData, int *pColorMeshID );
|
||||
void R_StudioDestroyStaticMeshes( int numStudioMeshes, studiomeshdata_t **ppStudioMeshes );
|
||||
|
||||
// Determine if any strip groups shouldn't be morphed
|
||||
void DetermineHWMorphing( mstudiomodel_t *pModel, OptimizedModel::ModelLODHeader_t *pVtxLOD );
|
||||
|
||||
// Count deltas affecting a particular stripgroup
|
||||
int CountDeltaFlexedStripGroups( mstudiomodel_t *pModel, OptimizedModel::ModelLODHeader_t *pVtxLOD );
|
||||
|
||||
// Count vertices affected by deltas in a particular strip group
|
||||
int CountFlexedVertices( mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t* pStripGroup );
|
||||
|
||||
// Builds morph data
|
||||
void R_StudioBuildMorph( studiohdr_t *pStudioHdr, studiomeshgroup_t* pMeshGroup, mstudiomesh_t* pMesh,
|
||||
OptimizedModel::StripGroupHeader_t *pStripGroup );
|
||||
|
||||
// Builds the decal bone remap for a particular mesh
|
||||
void ComputeHWMorphDecalBoneRemap( studiohdr_t *pStudioHdr, OptimizedModel::FileHeader_t *pVtxHdr, studiohwdata_t *pStudioHWData, int nLOD );
|
||||
void BuildDecalBoneMap( studiohdr_t *pStudioHdr, int *pUsedBones, int *pBoneRemap, int *pMaxBoneCount, mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t* pStripGroup );
|
||||
|
||||
// Helper methods used to construct static meshes
|
||||
int GetNumBoneWeights( const OptimizedModel::StripGroupHeader_t *pGroup );
|
||||
VertexFormat_t CalculateVertexFormat( const studiohdr_t *pStudioHdr, const studioloddata_t *pStudioLodData,
|
||||
const mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t *pGroup, bool bIsHwSkinned );
|
||||
VertexStreamSpec_t *CalculateStreamSpec( const studiohdr_t *pStudioHdr, const studioloddata_t *pStudioLodData,
|
||||
const mstudiomesh_t* pMesh, OptimizedModel::StripGroupHeader_t *pGroup, bool bIsHwSkinned, VertexFormat_t *pVertexFormat );
|
||||
bool MeshNeedsTangentSpace( studiohdr_t *pStudioHdr, studioloddata_t *pStudioLodData, mstudiomesh_t* pMesh );
|
||||
void R_StudioBuildMeshGroup( const char *pModelName, bool bNeedsTangentSpace, studioloddata_t *pStudioLodData,
|
||||
studiomeshgroup_t* pMeshGroup, OptimizedModel::StripGroupHeader_t *pStripGroup, mstudiomesh_t* pMesh,
|
||||
studiohdr_t *pStudioHdr, VertexFormat_t vertexFormat, VertexStreamSpec_t *pStreamSpec );
|
||||
void R_StudioBuildMeshStrips( studiomeshgroup_t* pMeshGroup,
|
||||
OptimizedModel::StripGroupHeader_t *pStripGroup );
|
||||
template <VertexCompressionType_t T> bool R_AddVertexToMesh( const char *pModelName, bool bNeedsTangentSpace, CMeshBuilder& meshBuilder,
|
||||
OptimizedModel::Vertex_t* pVertex, mstudiomesh_t* pMesh, const mstudio_meshvertexdata_t *vertData, bool hwSkin, bool bExtraUv );
|
||||
|
||||
// This will generate random flex data that has a specified # of non-zero values
|
||||
void GenerateRandomFlexWeights( int nWeightCount, float* pWeights, float *pDelayedWeights );
|
||||
|
||||
// Computes LOD
|
||||
int ComputeRenderLOD( IMatRenderContext *pRenderContext, const DrawModelInfo_t& info, const Vector &origin, float *pMetric );
|
||||
|
||||
// This invokes proxies of all materials that are queued to be rendered
|
||||
void InvokeBindProxies( IMatRenderContext *pRenderContext, ICallQueue *pCallQueue, const DrawModelInfo_t &info );
|
||||
|
||||
private:
|
||||
StudioRenderContext_t m_RC;
|
||||
|
||||
// Used by the lighting computation methods,
|
||||
// this is only here to prevent constructors in lightpos_t from being repeatedly run
|
||||
lightpos_t m_pLightPos[MAXLIGHTCOMPUTE];
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Inline methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline int CStudioRenderContext::ComputeModelLod( studiohwdata_t *pHardwareData, float flUnitSphereSize, float *pMetric )
|
||||
{
|
||||
return ComputeModelLODAndMetric( pHardwareData, flUnitSphereSize, pMetric );
|
||||
}
|
||||
|
||||
|
||||
#endif // STUDIORENDERCONTEXT_H
|
||||
2
studiorender/vsi.nul
Normal file
2
studiorender/vsi.nul
Normal file
@@ -0,0 +1,2 @@
|
||||
SN Visual Studio Integration
|
||||
IMPORTANT: Do not remove the custom build step for this file
|
||||
3
studiorender/xbox/xbox.def
Normal file
3
studiorender/xbox/xbox.def
Normal file
@@ -0,0 +1,3 @@
|
||||
LIBRARY StudioRender_360.dll
|
||||
EXPORTS
|
||||
CreateInterface @1
|
||||
Reference in New Issue
Block a user