This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

View 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:

View 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 );
}

View 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

View 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
View 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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 );
}
}

View 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 ) );
}
}
}
}
}
}

View 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 );
}

View 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

View 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 );
}

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

1048
studiorender/studiorender.h Normal file

File diff suppressed because it is too large Load Diff

View 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
}
}

View File

@@ -0,0 +1,13 @@
"vpc_cache"
{
"CacheVersion" "1"
"win32"
{
"CRCFile" "studiorender.vcxproj.vpc_crc"
"OutputFiles"
{
"0" "studiorender.vcxproj"
"1" "studiorender.vcxproj.filters"
}
}
}

File diff suppressed because it is too large Load Diff

View 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
View File

@@ -0,0 +1,2 @@
SN Visual Studio Integration
IMPORTANT: Do not remove the custom build step for this file

View File

@@ -0,0 +1,3 @@
LIBRARY StudioRender_360.dll
EXPORTS
CreateInterface @1