1
This commit is contained in:
235
tier2/beamsegdraw.cpp
Normal file
235
tier2/beamsegdraw.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/beamsegdraw.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// CBeamSegDraw implementation.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBeamSegDraw::Start( IMatRenderContext *pRenderContext, int nSegs, IMaterial *pMaterial, CMeshBuilder *pMeshBuilder, int nMeshVertCount )
|
||||
{
|
||||
m_pRenderContext = pRenderContext;
|
||||
Assert( nSegs >= 2 );
|
||||
|
||||
m_nSegsDrawn = 0;
|
||||
m_nTotalSegs = nSegs;
|
||||
|
||||
if ( pMeshBuilder )
|
||||
{
|
||||
m_pMeshBuilder = pMeshBuilder;
|
||||
m_nMeshVertCount = nMeshVertCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pMeshBuilder = NULL;
|
||||
m_nMeshVertCount = 0;
|
||||
|
||||
IMesh *pMesh = m_pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
|
||||
m_Mesh.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, (nSegs-1) * 2 );
|
||||
}
|
||||
}
|
||||
|
||||
inline void CBeamSegDraw::ComputeNormal( const Vector &vecCameraPos, const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal )
|
||||
{
|
||||
// vTangentY = line vector for beam
|
||||
Vector vTangentY;
|
||||
VectorSubtract( vStartPos, vNextPos, vTangentY );
|
||||
|
||||
// vDirToBeam = vector from viewer origin to beam
|
||||
Vector vDirToBeam;
|
||||
VectorSubtract( vStartPos, vecCameraPos, vDirToBeam );
|
||||
|
||||
// Get a vector that is perpendicular to us and perpendicular to the beam.
|
||||
// This is used to fatten the beam.
|
||||
CrossProduct( vTangentY, vDirToBeam, *pNormal );
|
||||
VectorNormalizeFast( *pNormal );
|
||||
}
|
||||
|
||||
inline void CBeamSegDraw::SpecifySeg( const Vector &vecCameraPos, const Vector &vNormal )
|
||||
{
|
||||
// SUCKY: Need to do a fair amount more work to get the tangent owing to the averaged normal
|
||||
Vector vDirToBeam, vTangentY;
|
||||
VectorSubtract( m_Seg.m_vPos, vecCameraPos, vDirToBeam );
|
||||
CrossProduct( vDirToBeam, vNormal, vTangentY );
|
||||
VectorNormalizeFast( vTangentY );
|
||||
|
||||
// Build the endpoints.
|
||||
Vector vPoint1, vPoint2;
|
||||
VectorMA( m_Seg.m_vPos, m_Seg.m_flWidth*0.5f, vNormal, vPoint1 );
|
||||
VectorMA( m_Seg.m_vPos, -m_Seg.m_flWidth*0.5f, vNormal, vPoint2 );
|
||||
|
||||
if ( m_pMeshBuilder )
|
||||
{
|
||||
// Specify the points.
|
||||
m_pMeshBuilder->Position3fv( vPoint1.Base() );
|
||||
m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha );
|
||||
m_pMeshBuilder->TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
|
||||
m_pMeshBuilder->TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
|
||||
m_pMeshBuilder->TangentS3fv( vNormal.Base() );
|
||||
m_pMeshBuilder->TangentT3fv( vTangentY.Base() );
|
||||
m_pMeshBuilder->AdvanceVertex();
|
||||
|
||||
m_pMeshBuilder->Position3fv( vPoint2.Base() );
|
||||
m_pMeshBuilder->Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha );
|
||||
m_pMeshBuilder->TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
|
||||
m_pMeshBuilder->TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
|
||||
m_pMeshBuilder->TangentS3fv( vNormal.Base() );
|
||||
m_pMeshBuilder->TangentT3fv( vTangentY.Base() );
|
||||
m_pMeshBuilder->AdvanceVertex();
|
||||
|
||||
if ( m_nSegsDrawn > 1 )
|
||||
{
|
||||
int nBase = ( ( m_nSegsDrawn - 2 ) * 2 ) + m_nMeshVertCount;
|
||||
|
||||
m_pMeshBuilder->FastIndex( nBase );
|
||||
m_pMeshBuilder->FastIndex( nBase + 1 );
|
||||
m_pMeshBuilder->FastIndex( nBase + 2 );
|
||||
m_pMeshBuilder->FastIndex( nBase + 1 );
|
||||
m_pMeshBuilder->FastIndex( nBase + 3 );
|
||||
m_pMeshBuilder->FastIndex( nBase + 2 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Specify the points.
|
||||
m_Mesh.Position3fv( vPoint1.Base() );
|
||||
m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha );
|
||||
m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TangentS3fv( vNormal.Base() );
|
||||
m_Mesh.TangentT3fv( vTangentY.Base() );
|
||||
m_Mesh.AdvanceVertex();
|
||||
|
||||
m_Mesh.Position3fv( vPoint2.Base() );
|
||||
m_Mesh.Color4f( VectorExpand( m_Seg.m_vColor ), m_Seg.m_flAlpha );
|
||||
m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TangentS3fv( vNormal.Base() );
|
||||
m_Mesh.TangentT3fv( vTangentY.Base() );
|
||||
m_Mesh.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
void CBeamSegDraw::NextSeg( BeamSeg_t *pSeg )
|
||||
{
|
||||
Vector vecCameraPos;
|
||||
m_pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
|
||||
|
||||
if ( m_nSegsDrawn > 0 )
|
||||
{
|
||||
// Get a vector that is perpendicular to us and perpendicular to the beam.
|
||||
// This is used to fatten the beam.
|
||||
Vector vNormal, vAveNormal;
|
||||
ComputeNormal( vecCameraPos, m_Seg.m_vPos, pSeg->m_vPos, &vNormal );
|
||||
|
||||
if ( m_nSegsDrawn > 1 )
|
||||
{
|
||||
// Average this with the previous normal
|
||||
VectorAdd( vNormal, m_vNormalLast, vAveNormal );
|
||||
vAveNormal *= 0.5f;
|
||||
VectorNormalizeFast( vAveNormal );
|
||||
}
|
||||
else
|
||||
{
|
||||
vAveNormal = vNormal;
|
||||
}
|
||||
|
||||
m_vNormalLast = vNormal;
|
||||
SpecifySeg( vecCameraPos, vAveNormal );
|
||||
}
|
||||
|
||||
m_Seg = *pSeg;
|
||||
++m_nSegsDrawn;
|
||||
|
||||
if( m_nSegsDrawn == m_nTotalSegs )
|
||||
{
|
||||
SpecifySeg( vecCameraPos, m_vNormalLast );
|
||||
}
|
||||
}
|
||||
|
||||
void CBeamSegDraw::End()
|
||||
{
|
||||
if ( m_pMeshBuilder )
|
||||
{
|
||||
m_pMeshBuilder = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Mesh.End( false, true );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBeamSegDrawArbitrary::SetNormal( const Vector &normal )
|
||||
{
|
||||
m_vNormalLast = normal;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBeamSegDrawArbitrary::NextSeg( BeamSeg_t *pSeg )
|
||||
{
|
||||
if ( m_nSegsDrawn > 0 )
|
||||
{
|
||||
Vector segDir = ( m_PrevSeg.m_vPos - pSeg->m_vPos );
|
||||
VectorNormalize( segDir );
|
||||
|
||||
Vector normal = CrossProduct( segDir, m_vNormalLast );
|
||||
SpecifySeg( normal );
|
||||
}
|
||||
|
||||
m_PrevSeg = m_Seg;
|
||||
m_Seg = *pSeg;
|
||||
++m_nSegsDrawn;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &vNextPos -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBeamSegDrawArbitrary::SpecifySeg( const Vector &vNormal )
|
||||
{
|
||||
// Build the endpoints.
|
||||
Vector vPoint1, vPoint2;
|
||||
Vector vDelta;
|
||||
VectorMultiply( vNormal, m_Seg.m_flWidth*0.5f, vDelta );
|
||||
VectorAdd( m_Seg.m_vPos, vDelta, vPoint1 );
|
||||
VectorSubtract( m_Seg.m_vPos, vDelta, vPoint2 );
|
||||
|
||||
// Specify the points.
|
||||
Assert( IsFinite(m_Seg.m_vColor.x) && IsFinite(m_Seg.m_vColor.y) && IsFinite(m_Seg.m_vColor.z) && IsFinite(m_Seg.m_flAlpha) );
|
||||
Assert( (m_Seg.m_vColor.x >= 0.0) && (m_Seg.m_vColor.y >= 0.0) && (m_Seg.m_vColor.z >= 0.0) && (m_Seg.m_flAlpha >= 0.0) );
|
||||
Assert( (m_Seg.m_vColor.x <= 1.0) && (m_Seg.m_vColor.y <= 1.0) && (m_Seg.m_vColor.z <= 1.0) && (m_Seg.m_flAlpha <= 1.0) );
|
||||
|
||||
unsigned char r = FastFToC( m_Seg.m_vColor.x );
|
||||
unsigned char g = FastFToC( m_Seg.m_vColor.y );
|
||||
unsigned char b = FastFToC( m_Seg.m_vColor.z );
|
||||
unsigned char a = FastFToC( m_Seg.m_flAlpha );
|
||||
m_Mesh.Position3fv( vPoint1.Base() );
|
||||
m_Mesh.Color4ub( r, g, b, a );
|
||||
m_Mesh.TexCoord2f( 0, 0, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TexCoord2f( 1, 0, m_Seg.m_flTexCoord );
|
||||
m_Mesh.AdvanceVertex();
|
||||
|
||||
m_Mesh.Position3fv( vPoint2.Base() );
|
||||
m_Mesh.Color4ub( r, g, b, a );
|
||||
m_Mesh.TexCoord2f( 0, 1, m_Seg.m_flTexCoord );
|
||||
m_Mesh.TexCoord2f( 1, 1, m_Seg.m_flTexCoord );
|
||||
m_Mesh.AdvanceVertex();
|
||||
}
|
99
tier2/camerautils.cpp
Normal file
99
tier2/camerautils.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
#include "tier2/camerautils.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "mathlib/vector.h"
|
||||
#include "mathlib/vmatrix.h"
|
||||
#include "tier2/tier2.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// accessors for generated matrices
|
||||
//-----------------------------------------------------------------------------
|
||||
void ComputeViewMatrix( matrix3x4_t *pWorldToCamera, const Camera_t &camera )
|
||||
{
|
||||
matrix3x4_t transform;
|
||||
AngleMatrix( camera.m_angles, camera.m_origin, transform );
|
||||
|
||||
VMatrix matRotate( transform );
|
||||
VMatrix matRotateZ;
|
||||
MatrixBuildRotationAboutAxis( matRotateZ, Vector(0,0,1), -90 );
|
||||
MatrixMultiply( matRotate, matRotateZ, matRotate );
|
||||
|
||||
VMatrix matRotateX;
|
||||
MatrixBuildRotationAboutAxis( matRotateX, Vector(1,0,0), 90 );
|
||||
MatrixMultiply( matRotate, matRotateX, matRotate );
|
||||
transform = matRotate.As3x4();
|
||||
|
||||
MatrixInvert( transform, *pWorldToCamera );
|
||||
}
|
||||
|
||||
void ComputeViewMatrix( VMatrix *pWorldToCamera, const Camera_t &camera )
|
||||
{
|
||||
matrix3x4_t transform, invTransform;
|
||||
AngleMatrix( camera.m_angles, camera.m_origin, transform );
|
||||
|
||||
VMatrix matRotate( transform );
|
||||
VMatrix matRotateZ;
|
||||
MatrixBuildRotationAboutAxis( matRotateZ, Vector(0,0,1), -90 );
|
||||
MatrixMultiply( matRotate, matRotateZ, matRotate );
|
||||
|
||||
VMatrix matRotateX;
|
||||
MatrixBuildRotationAboutAxis( matRotateX, Vector(1,0,0), 90 );
|
||||
MatrixMultiply( matRotate, matRotateX, matRotate );
|
||||
transform = matRotate.As3x4();
|
||||
|
||||
MatrixInvert( transform, invTransform );
|
||||
*pWorldToCamera = invTransform;
|
||||
}
|
||||
|
||||
void ComputeProjectionMatrix( VMatrix *pCameraToProjection, const Camera_t &camera, int width, int height )
|
||||
{
|
||||
float flFOV = camera.m_flFOV;
|
||||
float flZNear = camera.m_flZNear;
|
||||
float flZFar = camera.m_flZFar;
|
||||
float flApsectRatio = (float)width / (float)height;
|
||||
|
||||
// MatrixBuildPerspective( proj, flFOV, flFOV * flApsectRatio, flZNear, flZFar );
|
||||
|
||||
#if 1
|
||||
float halfWidth = tan( flFOV * M_PI / 360.0 );
|
||||
float halfHeight = halfWidth / flApsectRatio;
|
||||
#else
|
||||
float halfHeight = tan( flFOV * M_PI / 360.0 );
|
||||
float halfWidth = flApsectRatio * halfHeight;
|
||||
#endif
|
||||
memset( pCameraToProjection, 0, sizeof( VMatrix ) );
|
||||
pCameraToProjection->m[0][0] = 1.0f / halfWidth;
|
||||
pCameraToProjection->m[1][1] = 1.0f / halfHeight;
|
||||
pCameraToProjection->m[2][2] = flZFar / ( flZNear - flZFar );
|
||||
pCameraToProjection->m[3][2] = -1.0f;
|
||||
pCameraToProjection->m[2][3] = flZNear * flZFar / ( flZNear - flZFar );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes the screen space position given a screen size
|
||||
//-----------------------------------------------------------------------------
|
||||
void ComputeScreenSpacePosition( Vector2D *pScreenPosition, const Vector &vecWorldPosition,
|
||||
const Camera_t &camera, int width, int height )
|
||||
{
|
||||
VMatrix view, proj, viewproj;
|
||||
ComputeViewMatrix( &view, camera );
|
||||
ComputeProjectionMatrix( &proj, camera, width, height );
|
||||
MatrixMultiply( proj, view, viewproj );
|
||||
|
||||
Vector vecScreenPos;
|
||||
Vector3DMultiplyPositionProjective( viewproj, vecWorldPosition, vecScreenPos );
|
||||
|
||||
pScreenPosition->x = ( vecScreenPos.x + 1.0f ) * width / 2.0f;
|
||||
pScreenPosition->y = ( -vecScreenPos.y + 1.0f ) * height / 2.0f;
|
||||
}
|
||||
|
||||
|
57
tier2/defaultfilesystem.cpp
Normal file
57
tier2/defaultfilesystem.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A higher level link library for general use in the game and tools.
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include <tier0/platform.h>
|
||||
#include <tier2/tier2.h>
|
||||
#include <filesystem_init.h>
|
||||
|
||||
|
||||
static CSysModule *g_pFullFileSystemModule = NULL;
|
||||
|
||||
void* DefaultCreateInterfaceFn(const char *pName, int *pReturnCode)
|
||||
{
|
||||
if ( pReturnCode )
|
||||
{
|
||||
*pReturnCode = 0;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void InitDefaultFileSystem( void )
|
||||
{
|
||||
AssertMsg( !g_pFullFileSystem, "Already set up the file system" );
|
||||
|
||||
if ( !Sys_LoadInterface( "filesystem_stdio", FILESYSTEM_INTERFACE_VERSION,
|
||||
&g_pFullFileSystemModule, (void**)&g_pFullFileSystem ) )
|
||||
{
|
||||
if ( !Sys_LoadInterface( "filesystem_steam", FILESYSTEM_INTERFACE_VERSION,
|
||||
&g_pFullFileSystemModule, (void**)&g_pFullFileSystem ) )
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !g_pFullFileSystem->Connect( DefaultCreateInterfaceFn ) )
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ( g_pFullFileSystem->Init() != INIT_OK )
|
||||
{
|
||||
exit(0);
|
||||
}
|
||||
|
||||
g_pFullFileSystem->RemoveAllSearchPaths();
|
||||
g_pFullFileSystem->AddSearchPath( "", "LOCAL", PATH_ADD_TO_HEAD );
|
||||
}
|
||||
|
||||
void ShutdownDefaultFileSystem(void)
|
||||
{
|
||||
AssertMsg( g_pFullFileSystem, "File system not set up" );
|
||||
g_pFullFileSystem->Shutdown();
|
||||
g_pFullFileSystem->Disconnect();
|
||||
Sys_UnloadModule( g_pFullFileSystemModule );
|
||||
}
|
62
tier2/dmconnect.cpp
Normal file
62
tier2/dmconnect.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A higher level link library for general use in the game and tools.
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include <tier2/tier2.h>
|
||||
#include "datamodel/idatamodel.h"
|
||||
#include "dmserializers/idmserializers.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set up methods related to datamodel interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ConnectDataModel( CreateInterfaceFn factory )
|
||||
{
|
||||
if ( !g_pDataModel->Connect( factory ) )
|
||||
return false;
|
||||
|
||||
if ( !g_pDmElementFramework->Connect( factory ) )
|
||||
return false;
|
||||
|
||||
if ( !g_pDmSerializers->Connect( factory ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
InitReturnVal_t InitDataModel()
|
||||
{
|
||||
InitReturnVal_t nRetVal;
|
||||
|
||||
nRetVal = g_pDataModel->Init( );
|
||||
if ( nRetVal != INIT_OK )
|
||||
return nRetVal;
|
||||
|
||||
nRetVal = g_pDmElementFramework->Init();
|
||||
if ( nRetVal != INIT_OK )
|
||||
return nRetVal;
|
||||
|
||||
nRetVal = g_pDmSerializers->Init();
|
||||
if ( nRetVal != INIT_OK )
|
||||
return nRetVal;
|
||||
|
||||
return INIT_OK;
|
||||
}
|
||||
|
||||
void ShutdownDataModel()
|
||||
{
|
||||
g_pDmSerializers->Shutdown();
|
||||
g_pDmElementFramework->Shutdown();
|
||||
g_pDataModel->Shutdown( );
|
||||
}
|
||||
|
||||
void DisconnectDataModel()
|
||||
{
|
||||
g_pDmSerializers->Disconnect();
|
||||
g_pDmElementFramework->Disconnect();
|
||||
g_pDataModel->Disconnect();
|
||||
}
|
||||
|
||||
|
304
tier2/fileutils.cpp
Normal file
304
tier2/fileutils.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Helper methods + classes for file access
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/fileutils.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "filesystem.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
// NOTE: This has to be the last file included!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Builds a directory which is a subdirectory of the current mod
|
||||
//-----------------------------------------------------------------------------
|
||||
void GetModSubdirectory( const char *pSubDir, char *pBuf, int nBufLen )
|
||||
{
|
||||
// Compute starting directory
|
||||
Assert( g_pFullFileSystem->GetSearchPath( "MOD_WRITE", false, NULL, 0 ) < nBufLen );
|
||||
if ( g_pFullFileSystem->GetSearchPath( "MOD_WRITE", false, pBuf, nBufLen ) == 0 )
|
||||
{
|
||||
// if we didn't find MOD_WRITE, back to the old MOD
|
||||
Assert( g_pFullFileSystem->GetSearchPath( "MOD", false, NULL, 0 ) < nBufLen );
|
||||
g_pFullFileSystem->GetSearchPath( "MOD", false, pBuf, nBufLen );
|
||||
}
|
||||
|
||||
char *pSemi = strchr( pBuf, ';' );
|
||||
if ( pSemi )
|
||||
{
|
||||
*pSemi = 0;
|
||||
}
|
||||
|
||||
Q_StripTrailingSlash( pBuf );
|
||||
if ( pSubDir )
|
||||
{
|
||||
int nLen = Q_strlen( pSubDir );
|
||||
Q_strncat( pBuf, "\\", nBufLen, 1 );
|
||||
Q_strncat( pBuf, pSubDir, nBufLen, nLen );
|
||||
}
|
||||
|
||||
Q_FixSlashes( pBuf );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Builds a directory which is a subdirectory of the current mod's *content*
|
||||
//-----------------------------------------------------------------------------
|
||||
void GetModContentSubdirectory( const char *pSubDir, char *pBuf, int nBufLen )
|
||||
{
|
||||
char pTemp[ MAX_PATH ];
|
||||
GetModSubdirectory( pSubDir, pTemp, sizeof(pTemp) );
|
||||
ComputeModContentFilename( pTemp, pBuf, nBufLen );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generates a filename under the 'game' subdirectory given a subdirectory of 'content'
|
||||
//-----------------------------------------------------------------------------
|
||||
void ComputeModFilename( const char *pContentFileName, char *pBuf, size_t nBufLen )
|
||||
{
|
||||
char pRelativePath[ MAX_PATH ];
|
||||
if ( !g_pFullFileSystem->FullPathToRelativePathEx( pContentFileName, "CONTENTROOT", pRelativePath, sizeof(pRelativePath) ) )
|
||||
{
|
||||
Q_strncpy( pBuf, pContentFileName, (int)nBufLen );
|
||||
return;
|
||||
}
|
||||
|
||||
char pGameRoot[ MAX_PATH ];
|
||||
g_pFullFileSystem->GetSearchPath( "GAMEROOT", false, pGameRoot, sizeof(pGameRoot) );
|
||||
char *pSemi = strchr( pGameRoot, ';' );
|
||||
if ( pSemi )
|
||||
{
|
||||
*pSemi = 0;
|
||||
}
|
||||
|
||||
Q_ComposeFileName( pGameRoot, pRelativePath, pBuf, (int)nBufLen );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generates a filename under the 'content' subdirectory given a subdirectory of 'game'
|
||||
//-----------------------------------------------------------------------------
|
||||
void ComputeModContentFilename( const char *pGameFileName, char *pBuf, size_t nBufLen )
|
||||
{
|
||||
char pRelativePath[ MAX_PATH ];
|
||||
if ( !g_pFullFileSystem->FullPathToRelativePathEx( pGameFileName, "GAMEROOT", pRelativePath, sizeof(pRelativePath) ) )
|
||||
{
|
||||
Q_strncpy( pBuf, pGameFileName, (int)nBufLen );
|
||||
return;
|
||||
}
|
||||
|
||||
char pContentRoot[ MAX_PATH ];
|
||||
g_pFullFileSystem->GetSearchPath( "CONTENTROOT", false, pContentRoot, sizeof(pContentRoot) );
|
||||
char *pSemi = strchr( pContentRoot, ';' );
|
||||
if ( pSemi )
|
||||
{
|
||||
*pSemi = 0;
|
||||
}
|
||||
|
||||
Q_ComposeFileName( pContentRoot, pRelativePath, pBuf, (int)nBufLen );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generates an Xbox 360 filename from a PC filename
|
||||
//-----------------------------------------------------------------------------
|
||||
char *CreateX360Filename( const char *pSourceName, char *pTargetName, int targetLen )
|
||||
{
|
||||
Q_StripExtension( pSourceName, pTargetName, targetLen );
|
||||
int idx = Q_strlen( pTargetName );
|
||||
|
||||
// restore extension
|
||||
Q_snprintf( pTargetName, targetLen, "%s.360%s", pTargetName, &pSourceName[idx] );
|
||||
|
||||
return pTargetName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Generates a PC filename from a possible 360 name.
|
||||
// Strips the .360. from filename.360.extension.
|
||||
// Filenames might have multiple '.', need to be careful and only consider the
|
||||
// last true extension. Complex filenames do occur:
|
||||
// d:\foo\.\foo.dat
|
||||
// d:\zip0.360.zip\foo.360.dat
|
||||
// Returns source if no change needs to occur, othwerwise generates and
|
||||
// returns target.
|
||||
//-----------------------------------------------------------------------------
|
||||
char *RestoreFilename( const char *pSourceName, char *pTargetName, int targetLen )
|
||||
{
|
||||
// find extension
|
||||
// scan backward for '.', but not past a seperator
|
||||
int end = V_strlen( pSourceName ) - 1;
|
||||
while ( end > 0 && pSourceName[end] != '.' && !( pSourceName[end] == '\\' || pSourceName[end] == '/' ) )
|
||||
{
|
||||
--end;
|
||||
}
|
||||
|
||||
if ( end >= 4 && pSourceName[end] == '.' && !V_strncmp( pSourceName + end - 4 , ".360", 4 ) )
|
||||
{
|
||||
// cull the .360, leave the trailing extension
|
||||
end -= 4;
|
||||
int length = MIN( end + 1, targetLen );
|
||||
V_strncpy( pTargetName, pSourceName, length );
|
||||
V_strncat( pTargetName, pSourceName + end + 4, targetLen );
|
||||
|
||||
return pTargetName;
|
||||
}
|
||||
|
||||
// source filename is as expected
|
||||
return (char *)pSourceName;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Generate an Xbox 360 file if it doesn't exist or is out of date. This function determines
|
||||
// the source and target path and whether the file needs to be generated. The caller provides
|
||||
// a callback function to do the actual creation of the 360 file. "pExtraData" is for the caller to
|
||||
// pass the address of any data that the callback function may need to access. This function
|
||||
// is ONLY to be called by caller's who expect to have 360 versions of their file.
|
||||
//-----------------------------------------------------------------------------
|
||||
int UpdateOrCreate( const char *pSourceName, char *pTargetName, int targetLen, const char *pPathID, CreateCallback_t pfnCreate, bool bForce, void *pExtraData )
|
||||
{
|
||||
if ( pTargetName )
|
||||
{
|
||||
// caller could supply source as PC or 360 name, we want the PC filename
|
||||
char szFixedSourceName[MAX_PATH];
|
||||
pSourceName = RestoreFilename( pSourceName, szFixedSourceName, sizeof( szFixedSourceName ) );
|
||||
// caller wants us to provide 360 named version of source
|
||||
CreateX360Filename( pSourceName, pTargetName, targetLen );
|
||||
}
|
||||
|
||||
// no conversion are performed by the game at runtime anymore
|
||||
// SMB access was removed by the XDK for Vista....
|
||||
return UOC_NOT_CREATED;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the search path as a list of paths
|
||||
//-----------------------------------------------------------------------------
|
||||
void GetSearchPath( CUtlVector< CUtlString > &path, const char *pPathID )
|
||||
{
|
||||
int nMaxLen = g_pFullFileSystem->GetSearchPath( pPathID, false, NULL, 0 );
|
||||
char *pBuf = (char*)stackalloc( nMaxLen );
|
||||
g_pFullFileSystem->GetSearchPath( pPathID, false, pBuf, nMaxLen );
|
||||
|
||||
char *pSemi;
|
||||
while ( NULL != ( pSemi = strchr( pBuf, ';' ) ) )
|
||||
{
|
||||
*pSemi = 0;
|
||||
path.AddToTail( pBuf );
|
||||
pBuf = pSemi + 1;
|
||||
}
|
||||
path.AddToTail( pBuf );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Given file name in the current dir generate a full path to it.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GenerateFullPath( const char *pFileName, char const *pPathID, char *pBuf, int nBufLen )
|
||||
{
|
||||
if ( V_IsAbsolutePath( pFileName ) )
|
||||
{
|
||||
V_strncpy( pBuf, pFileName, nBufLen );
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *pFullPath = g_pFullFileSystem->RelativePathToFullPath( pFileName, pPathID, pBuf, nBufLen );
|
||||
if ( pFullPath && Q_IsAbsolutePath( pFullPath ) )
|
||||
return true;
|
||||
|
||||
char pDir[ MAX_PATH ];
|
||||
if ( !g_pFullFileSystem->GetCurrentDirectory( pDir, sizeof( pDir ) ) )
|
||||
return false;
|
||||
|
||||
V_ComposeFileName( pDir, pFileName, pBuf, nBufLen );
|
||||
V_RemoveDotSlashes( pBuf );
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Builds a list of all files under a directory with a particular extension
|
||||
//-----------------------------------------------------------------------------
|
||||
void AddFilesToList( CUtlVector< CUtlString > &list, const char *pDirectory, const char *pPathID, const char *pExtension )
|
||||
{
|
||||
char pSearchString[MAX_PATH];
|
||||
Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pDirectory );
|
||||
|
||||
bool bIsAbsolute = Q_IsAbsolutePath( pDirectory );
|
||||
|
||||
// get the list of files
|
||||
FileFindHandle_t hFind;
|
||||
const char *pFoundFile = g_pFullFileSystem->FindFirstEx( pSearchString, pPathID, &hFind );
|
||||
|
||||
// add all the items
|
||||
CUtlVector< CUtlString > subDirs;
|
||||
for ( ; pFoundFile; pFoundFile = g_pFullFileSystem->FindNext( hFind ) )
|
||||
{
|
||||
char pChildPath[MAX_PATH];
|
||||
Q_snprintf( pChildPath, MAX_PATH, "%s\\%s", pDirectory, pFoundFile );
|
||||
|
||||
if ( g_pFullFileSystem->FindIsDirectory( hFind ) )
|
||||
{
|
||||
if ( Q_strnicmp( pFoundFile, ".", 2 ) && Q_strnicmp( pFoundFile, "..", 3 ) )
|
||||
{
|
||||
subDirs.AddToTail( pChildPath );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the extension matches
|
||||
const char *pExt = Q_GetFileExtension( pFoundFile );
|
||||
if ( !pExt || Q_stricmp( pExt, pExtension ) != 0 )
|
||||
continue;
|
||||
|
||||
char pFullPathBuf[MAX_PATH];
|
||||
char *pFullPath = pFullPathBuf;
|
||||
if ( !bIsAbsolute )
|
||||
{
|
||||
g_pFullFileSystem->RelativePathToFullPath( pChildPath, pPathID, pFullPathBuf, sizeof(pFullPathBuf) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pFullPath = pChildPath;
|
||||
}
|
||||
|
||||
V_strlower( pFullPath );
|
||||
Q_FixSlashes( pFullPath );
|
||||
list.AddToTail( pFullPath );
|
||||
}
|
||||
|
||||
g_pFullFileSystem->FindClose( hFind );
|
||||
|
||||
int nCount = subDirs.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
AddFilesToList( list, subDirs[i], pPathID, pExtension );
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseFile::ReadLines( CUtlStringList &lineList, int nMaxLineLength )
|
||||
{
|
||||
char *pLine = ( char * ) stackalloc( nMaxLineLength );
|
||||
while( ReadLine( pLine, nMaxLineLength ) )
|
||||
{
|
||||
char *pEOL = strchr( pLine, '\n' ); // kill the \n
|
||||
if ( pEOL )
|
||||
*pEOL = 0;
|
||||
lineList.CopyAndAddToTail( pLine );
|
||||
}
|
||||
}
|
||||
|
||||
void CBaseFile::ReadFile( CUtlBuffer &fileData )
|
||||
{
|
||||
int nFileSize = Size();
|
||||
fileData.EnsureCapacity( Size() );
|
||||
int nSize = Read( fileData.Base(), nFileSize );
|
||||
fileData.SeekPut( CUtlBuffer::SEEK_HEAD, nSize );
|
||||
}
|
||||
|
||||
|
143
tier2/keybindings.cpp
Normal file
143
tier2/keybindings.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/keybindings.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "inputsystem/iinputsystem.h"
|
||||
#include "tier1/utlbuffer.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set a key binding
|
||||
//-----------------------------------------------------------------------------
|
||||
void CKeyBindings::SetBinding( ButtonCode_t code, const char *pBinding )
|
||||
{
|
||||
if ( code == BUTTON_CODE_INVALID || code == KEY_NONE )
|
||||
return;
|
||||
|
||||
// free old bindings
|
||||
if ( !m_KeyInfo[code].IsEmpty() )
|
||||
{
|
||||
// Exactly the same, don't re-bind and fragment memory
|
||||
if ( !Q_stricmp( m_KeyInfo[code], pBinding ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate memory for new binding
|
||||
m_KeyInfo[code] = pBinding;
|
||||
}
|
||||
|
||||
void CKeyBindings::SetBinding( const char *pButtonName, const char *pBinding )
|
||||
{
|
||||
ButtonCode_t code = g_pInputSystem->StringToButtonCode( pButtonName );
|
||||
SetBinding( code, pBinding );
|
||||
}
|
||||
|
||||
void CKeyBindings::Unbind( ButtonCode_t code )
|
||||
{
|
||||
if ( code != KEY_NONE && code != BUTTON_CODE_INVALID )
|
||||
{
|
||||
m_KeyInfo[code] = "";
|
||||
}
|
||||
}
|
||||
|
||||
void CKeyBindings::Unbind( const char *pButtonName )
|
||||
{
|
||||
ButtonCode_t code = g_pInputSystem->StringToButtonCode( pButtonName );
|
||||
Unbind( code );
|
||||
}
|
||||
|
||||
void CKeyBindings::UnbindAll()
|
||||
{
|
||||
for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
m_KeyInfo[i] = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Count number of lines of bindings we'll be writing
|
||||
//-----------------------------------------------------------------------------
|
||||
int CKeyBindings::GetBindingCount( ) const
|
||||
{
|
||||
int nCount = 0;
|
||||
for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
if ( !m_KeyInfo[i].IsEmpty() )
|
||||
{
|
||||
nCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Writes lines containing "bind key value"
|
||||
//-----------------------------------------------------------------------------
|
||||
void CKeyBindings::WriteBindings( CUtlBuffer &buf )
|
||||
{
|
||||
for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
if ( !m_KeyInfo[i].IsEmpty() )
|
||||
{
|
||||
const char *pButtonCode = g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
buf.Printf( "bind \"%s\" \"%s\"\n", pButtonCode, m_KeyInfo[i].Get() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the keyname to which a binding string is bound. E.g., if
|
||||
// TAB is bound to +use then searching for +use will return "TAB"
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CKeyBindings::ButtonNameForBinding( const char *pBinding )
|
||||
{
|
||||
const char *pBind = pBinding;
|
||||
if ( pBinding[0] == '+' )
|
||||
{
|
||||
++pBind;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
|
||||
{
|
||||
if ( m_KeyInfo[i].IsEmpty() )
|
||||
continue;
|
||||
|
||||
if ( m_KeyInfo[i][0] == '+' )
|
||||
{
|
||||
if ( !Q_stricmp( &m_KeyInfo[i].Get()[1], pBind ) )
|
||||
return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !Q_stricmp( m_KeyInfo[i], pBind ) )
|
||||
return g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *CKeyBindings::GetBindingForButton( ButtonCode_t code )
|
||||
{
|
||||
if ( m_KeyInfo[code].IsEmpty() )
|
||||
return NULL;
|
||||
|
||||
return m_KeyInfo[ code ];
|
||||
}
|
||||
|
||||
|
||||
|
462
tier2/keyvaluesmacros.cpp
Normal file
462
tier2/keyvaluesmacros.cpp
Normal file
@ -0,0 +1,462 @@
|
||||
//===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
|
||||
//
|
||||
//==================================================================================================
|
||||
|
||||
|
||||
#include "filesystem.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "tier2/keyvaluesmacros.h"
|
||||
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Returns true if the passed string matches the filename style glob, false otherwise
|
||||
// * matches any characters, ? matches any single character, otherwise case insensitive matching
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
bool GlobMatch( const char *pszGlob, const char *pszString )
|
||||
{
|
||||
while ( ( *pszString != '\0' ) && ( *pszGlob != '*' ) )
|
||||
{
|
||||
if ( ( V_strnicmp( pszGlob, pszString, 1 ) != 0 ) && ( *pszGlob != '?' ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
++pszGlob;
|
||||
++pszString;
|
||||
}
|
||||
|
||||
const char *pszGlobTmp = nullptr;
|
||||
const char *pszStringTmp = nullptr;
|
||||
|
||||
while ( *pszString )
|
||||
{
|
||||
if ( *pszGlob == '*' )
|
||||
{
|
||||
++pszGlob;
|
||||
|
||||
if ( *pszGlob == '\0' )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pszGlobTmp = pszGlob;
|
||||
pszStringTmp = pszString + 1;
|
||||
}
|
||||
else if ( ( V_strnicmp( pszGlob, pszString, 1 ) == 0 ) || ( *pszGlob == '?' ) )
|
||||
{
|
||||
++pszGlob;
|
||||
++pszString;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszGlob = pszGlobTmp;
|
||||
pszString = pszStringTmp++;
|
||||
}
|
||||
}
|
||||
|
||||
while ( *pszGlob == '*' )
|
||||
{
|
||||
++pszGlob;
|
||||
}
|
||||
|
||||
return *pszGlob == '\0';
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Inserts pkvToInsert after pkvAfter but setting pkvAfter's NextKey to pkvInsert
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
static void InsertKeyValuesAfter( KeyValues *pkvAfter, KeyValues *pkvToInsert )
|
||||
{
|
||||
Assert( pkvAfter );
|
||||
Assert( pkvToInsert );
|
||||
|
||||
pkvToInsert->SetNextKey( pkvAfter->GetNextKey() );
|
||||
pkvAfter->SetNextKey( pkvToInsert );
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
static KeyValues *ReplaceSubKeyWithCopy( KeyValues *pkvParent, KeyValues *pkvToReplace, KeyValues *pkvReplaceWith )
|
||||
{
|
||||
Assert( pkvReplaceWith->GetFirstSubKey() == nullptr );
|
||||
|
||||
KeyValues *pkvCopy = pkvReplaceWith->MakeCopy();
|
||||
Assert( pkvCopy->GetFirstSubKey() == nullptr );
|
||||
Assert( pkvCopy->GetNextKey() == nullptr );
|
||||
|
||||
InsertKeyValuesAfter( pkvToReplace, pkvCopy );
|
||||
pkvParent->RemoveSubKey( pkvToReplace );
|
||||
pkvToReplace->deleteThis();
|
||||
|
||||
return pkvCopy;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Handles a KeyValues #insert macro. Replaces the #insert KeyValues with the specified file
|
||||
// if it can be loaded. This is not called #include because base KeyValue's already has #include
|
||||
// but it has two issues. The #include is relative to the keyvalues, these paths are resolved
|
||||
// normally via IFileSystem and #include only works at the top level, #insert works no matter
|
||||
// how deep the #insert macro is
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
static KeyValues *HandleKeyValuesMacro_Insert( KeyValues *pkvInsert, KeyValues *pkvParent )
|
||||
{
|
||||
const char *pszName = pkvInsert->GetName();
|
||||
|
||||
if ( V_stricmp( "#insert", pszName ) != 0 )
|
||||
return nullptr;
|
||||
|
||||
// Have an #insert key
|
||||
|
||||
if ( pkvInsert->GetFirstSubKey() )
|
||||
{
|
||||
// Invalid, has sub keys
|
||||
Msg( "Error: #insert on key with subkeys, can only do #insert with simple key/value with string value\n" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( pkvInsert->GetDataType() != KeyValues::TYPE_STRING )
|
||||
{
|
||||
// Invalid, value isn't a string
|
||||
Msg( "Error: #insert on key without a data type of string, can only do #insert with simple key/value with string value\n" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *pszInsert = pkvInsert->GetString();
|
||||
if ( !pszInsert && *pszInsert == '\0' )
|
||||
{
|
||||
// Invalid, value is empty string
|
||||
Msg( "Error: #insert on key with empty string value, can only do #insert with simple key/value with string value\n" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileHandle_t f = g_pFullFileSystem->Open( pszInsert, "rb" );
|
||||
if ( !f )
|
||||
{
|
||||
// Invalid, couldn't open #insert file
|
||||
Msg( "Error: #insert couldn't open file: %s\n", pszInsert );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint nFileSize = g_pFullFileSystem->Size( f );
|
||||
if ( nFileSize == 0 )
|
||||
{
|
||||
// Invalid, empty file
|
||||
Msg( "Error: #insert empty file: %s\n", pszInsert );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint nBufSize = g_pFullFileSystem->GetOptimalReadSize( f, nFileSize + 2 /* null termination */ + 8 /* "\"x\"\n{\n}\n" */ );
|
||||
char *pBuf = ( char* )g_pFullFileSystem->AllocOptimalReadBuffer( f, nBufSize );
|
||||
pBuf[0] = '"';
|
||||
pBuf[1] = 'i';
|
||||
pBuf[2] = '"';
|
||||
pBuf[3] = '\n';
|
||||
pBuf[4] = '{';
|
||||
pBuf[5] = '\n';
|
||||
|
||||
bool bRetOK = ( g_pFullFileSystem->ReadEx( pBuf + 6, nBufSize - 6, nFileSize, f ) != 0 );
|
||||
|
||||
g_pFullFileSystem->Close( f );
|
||||
|
||||
KeyValues *pkvNew = nullptr;
|
||||
|
||||
if ( bRetOK )
|
||||
{
|
||||
pBuf[nFileSize + 6 + 0] = '}';
|
||||
pBuf[nFileSize + 6 + 1] = '\n';
|
||||
pBuf[nFileSize + 6 + 2] = '\0';
|
||||
pBuf[nFileSize + 6 + 3] = '\0'; // Double NULL termination
|
||||
|
||||
pkvNew = new KeyValues( pszInsert );
|
||||
|
||||
bRetOK = pkvNew->LoadFromBuffer( pszInsert, pBuf, g_pFullFileSystem );
|
||||
}
|
||||
else
|
||||
{
|
||||
Msg( "Error: #insert couldn't read file: %s\n", pszInsert );
|
||||
}
|
||||
|
||||
g_pFullFileSystem->FreeOptimalReadBuffer( pBuf );
|
||||
|
||||
KeyValues *pkvReturn = nullptr;
|
||||
|
||||
CUtlVector< KeyValues * > newKeyList;
|
||||
|
||||
if ( bRetOK )
|
||||
{
|
||||
KeyValues *pkvInsertAfter = pkvInsert;
|
||||
|
||||
KeyValues *pkvNewSubKey = pkvNew->GetFirstSubKey();
|
||||
pkvReturn = pkvNewSubKey;
|
||||
|
||||
while ( pkvNewSubKey )
|
||||
{
|
||||
KeyValues *pkvNextNewSubKey = pkvNewSubKey->GetNextKey();
|
||||
|
||||
pkvNew->RemoveSubKey( pkvNewSubKey );
|
||||
|
||||
bool bFound = false;
|
||||
|
||||
if ( pkvNewSubKey->GetFirstSubKey() == nullptr )
|
||||
{
|
||||
for ( KeyValues *pkvChild = pkvParent->GetFirstSubKey(); pkvChild; pkvChild = pkvChild->GetNextKey() )
|
||||
{
|
||||
if ( pkvChild == pkvInsert )
|
||||
continue;
|
||||
|
||||
if ( pkvChild->GetNameSymbol() == pkvNewSubKey->GetNameSymbol() )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bFound )
|
||||
{
|
||||
InsertKeyValuesAfter( pkvInsertAfter, pkvNewSubKey );
|
||||
|
||||
pkvInsertAfter = pkvNewSubKey;
|
||||
|
||||
newKeyList.AddToTail( pkvNewSubKey );
|
||||
}
|
||||
|
||||
pkvNewSubKey = pkvNextNewSubKey;
|
||||
}
|
||||
|
||||
pkvParent->RemoveSubKey( pkvInsert );
|
||||
pkvInsert->deleteThis();
|
||||
}
|
||||
|
||||
if ( pkvNew )
|
||||
{
|
||||
pkvNew->deleteThis();
|
||||
}
|
||||
|
||||
for ( int i = 0; i < newKeyList.Count(); ++i )
|
||||
{
|
||||
HandleKeyValuesMacros( pkvParent, newKeyList[i] );
|
||||
}
|
||||
|
||||
return pkvReturn;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Merge pkvSrc over pkvDst, adding any new keys from src to dst but overwriting
|
||||
// existing keys in dst with keys with matching names from src
|
||||
//-----------------------------------------------------------------------------
|
||||
static void UpdateKeyValuesBlock( KeyValues *pkvDst, KeyValues *pkvUpdate )
|
||||
{
|
||||
Assert( pkvDst->GetFirstSubKey() );
|
||||
Assert( pkvUpdate->GetFirstSubKey() );
|
||||
|
||||
for ( KeyValues *pkvUpdateSubKey = pkvUpdate->GetFirstSubKey(); pkvUpdateSubKey; pkvUpdateSubKey = pkvUpdateSubKey->GetNextKey() )
|
||||
{
|
||||
const int nSrcName = pkvUpdateSubKey->GetNameSymbol();
|
||||
|
||||
if ( pkvUpdateSubKey->GetFirstSubKey() )
|
||||
{
|
||||
Msg( "Error: #update has a key with subkeys, only simple key/values are allowed for #update, skipping: %s\n", pkvUpdateSubKey->GetName() );
|
||||
continue;
|
||||
}
|
||||
|
||||
KeyValues *pkvNew = nullptr;
|
||||
|
||||
// Check for an existing key with the same name
|
||||
for ( KeyValues *pkvDstSubKey = pkvDst->GetFirstSubKey(); pkvDstSubKey; pkvDstSubKey = pkvDstSubKey->GetNextKey() )
|
||||
{
|
||||
if ( pkvDstSubKey == pkvUpdate )
|
||||
continue;
|
||||
|
||||
const int nDstName = pkvDstSubKey->GetNameSymbol();
|
||||
|
||||
if ( nSrcName == nDstName )
|
||||
{
|
||||
pkvNew = ReplaceSubKeyWithCopy( pkvDst, pkvDstSubKey, pkvUpdateSubKey );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !pkvNew )
|
||||
{
|
||||
// Didn't update an existing key, add a key
|
||||
pkvNew = pkvUpdateSubKey->MakeCopy();
|
||||
pkvDst->AddSubKey( pkvNew ); // TODO: Perhaps add this right after the #update block?
|
||||
}
|
||||
|
||||
Assert( pkvNew );
|
||||
|
||||
// Do inserts right away
|
||||
if ( !V_strcmp( pkvNew->GetName(), "#insert" ) )
|
||||
{
|
||||
while ( pkvNew )
|
||||
{
|
||||
pkvNew = HandleKeyValuesMacros( pkvNew, pkvDst );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Handle's #update macros
|
||||
//
|
||||
// An #update must be a KeyValue block with a KeyValue block as a parent. It will look at sibling
|
||||
// KeyValue blocks which match an optional "#glob", or all sibling KeyValue blocks if no "#glob" is
|
||||
// specified and will merge all of the #update block's subkeys into each sibling block.
|
||||
// overwriting KeyValues if they already exist and adding new KeyValues if they don't.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Before:
|
||||
//
|
||||
// "example"
|
||||
// {
|
||||
// "wear_level_1"
|
||||
// {
|
||||
// "one" "one_val"
|
||||
// "two" "two_val"
|
||||
// }
|
||||
// "wear_level_2"
|
||||
// {
|
||||
// "one" "one_val"
|
||||
// "two" "two_val"
|
||||
// }
|
||||
// "subblock"
|
||||
// {
|
||||
// "one" "one_val"
|
||||
// "two" "two_val"
|
||||
// }
|
||||
// "#update"
|
||||
// {
|
||||
// "#glob" "wear_level_*"
|
||||
// "one" "updated_one_val"
|
||||
// "three" "three_val"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// After:
|
||||
//
|
||||
// "example"
|
||||
// {
|
||||
// "wear_level_1"
|
||||
// {
|
||||
// "one" "updated_one_val"
|
||||
// "two" "two_val"
|
||||
// "three" "three_val"
|
||||
// }
|
||||
// "wear_level_2"
|
||||
// {
|
||||
// "one" "updated_one_val"
|
||||
// "two" "two_val"
|
||||
// "three" "three_val"
|
||||
// }
|
||||
// "subblock"
|
||||
// {
|
||||
// "one" "one_val"
|
||||
// "two" "two_val"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
static KeyValues *HandleKeyValuesMacro_Update( KeyValues *pkvUpdate, KeyValues *pkvParent, bool *pbDidUpdate )
|
||||
{
|
||||
const char *pszName = pkvUpdate->GetName();
|
||||
|
||||
if ( V_stricmp( "#update", pszName ) != 0 )
|
||||
return nullptr;
|
||||
|
||||
// Have an #update key
|
||||
|
||||
if ( pkvUpdate->GetFirstSubKey() == nullptr )
|
||||
{
|
||||
// Invalid, has sub keys
|
||||
Msg( "Error: #insert on key without subkeys, can only do #update with a key with subkeys\n" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( pkvUpdate->GetDataType() != KeyValues::TYPE_NONE )
|
||||
{
|
||||
// Invalid, value isn't a TYPE_NONE
|
||||
Msg( "Error: #update on key without a data type of NONE, can only do #update with a key with subkeys\n" );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *pszGlob = nullptr;
|
||||
|
||||
KeyValues *pkvGlob = pkvUpdate->FindKey( "#glob" );
|
||||
if ( !pkvGlob )
|
||||
{
|
||||
pkvGlob = pkvUpdate->FindKey( "glob" );
|
||||
}
|
||||
|
||||
if ( pkvGlob )
|
||||
{
|
||||
pszGlob = pkvGlob->GetString( nullptr, nullptr );
|
||||
pkvUpdate->RemoveSubKey( pkvGlob );
|
||||
}
|
||||
|
||||
for ( KeyValues *pkvParentSubKey = pkvParent->GetFirstSubKey(); pkvParentSubKey; pkvParentSubKey = pkvParentSubKey->GetNextKey() )
|
||||
{
|
||||
if ( pkvParentSubKey == pkvUpdate )
|
||||
continue;
|
||||
|
||||
if ( pszGlob && !GlobMatch( pszGlob, pkvParentSubKey->GetName() ) )
|
||||
continue;
|
||||
|
||||
UpdateKeyValuesBlock( pkvParentSubKey, pkvUpdate );
|
||||
}
|
||||
|
||||
KeyValues *pkvReturn = pkvUpdate->GetNextKey();
|
||||
|
||||
pkvParent->RemoveSubKey( pkvUpdate );
|
||||
pkvUpdate->deleteThis();
|
||||
|
||||
if ( pbDidUpdate )
|
||||
{
|
||||
*pbDidUpdate = true;
|
||||
}
|
||||
|
||||
return pkvReturn;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Main external extry point
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
KeyValues *HandleKeyValuesMacros( KeyValues *kv, KeyValues *pkvParent /* = nullptr */ )
|
||||
{
|
||||
KeyValues *pkvNextKey = HandleKeyValuesMacro_Insert( kv, pkvParent );
|
||||
if ( pkvNextKey )
|
||||
{
|
||||
Assert( kv->GetFirstSubKey() == nullptr );
|
||||
|
||||
return pkvNextKey;
|
||||
}
|
||||
|
||||
bool bDidLocalUpdate = false;
|
||||
pkvNextKey = HandleKeyValuesMacro_Update( kv, pkvParent, &bDidLocalUpdate );
|
||||
if ( bDidLocalUpdate )
|
||||
{
|
||||
Assert( kv->GetFirstSubKey() != nullptr );
|
||||
|
||||
return pkvNextKey;
|
||||
}
|
||||
|
||||
KeyValues *pkvSub = kv->GetFirstSubKey();
|
||||
while ( pkvSub )
|
||||
{
|
||||
pkvSub = HandleKeyValuesMacros( pkvSub, kv );
|
||||
}
|
||||
|
||||
return kv->GetNextKey();
|
||||
}
|
104
tier2/meshutils.cpp
Normal file
104
tier2/meshutils.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A set of utilities to render standard shapes
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/meshutils.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper methods to create various standard index buffer types
|
||||
//-----------------------------------------------------------------------------
|
||||
void GenerateSequentialIndexBuffer( unsigned short* pIndices, int nIndexCount, int nFirstVertex )
|
||||
{
|
||||
if ( !pIndices )
|
||||
return;
|
||||
|
||||
// Format the sequential buffer
|
||||
for ( int i = 0; i < nIndexCount; ++i )
|
||||
{
|
||||
pIndices[i] = (unsigned short)( i + nFirstVertex );
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateQuadIndexBuffer( unsigned short* pIndices, int nIndexCount, int nFirstVertex )
|
||||
{
|
||||
if ( !pIndices )
|
||||
return;
|
||||
|
||||
// Format the quad buffer
|
||||
int i;
|
||||
int numQuads = nIndexCount / 6;
|
||||
int baseVertex = nFirstVertex;
|
||||
for ( i = 0; i < numQuads; ++i)
|
||||
{
|
||||
// Triangle 1
|
||||
pIndices[0] = (unsigned short)( baseVertex );
|
||||
pIndices[1] = (unsigned short)( baseVertex + 1 );
|
||||
pIndices[2] = (unsigned short)( baseVertex + 2 );
|
||||
|
||||
// Triangle 2
|
||||
pIndices[3] = (unsigned short)( baseVertex );
|
||||
pIndices[4] = (unsigned short)( baseVertex + 2 );
|
||||
pIndices[5] = (unsigned short)( baseVertex + 3 );
|
||||
|
||||
baseVertex += 4;
|
||||
pIndices += 6;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratePolygonIndexBuffer( unsigned short* pIndices, int nIndexCount, int nFirstVertex )
|
||||
{
|
||||
if ( !pIndices )
|
||||
return;
|
||||
|
||||
int i;
|
||||
int numPolygons = nIndexCount / 3;
|
||||
for ( i = 0; i < numPolygons; ++i)
|
||||
{
|
||||
// Triangle 1
|
||||
pIndices[0] = (unsigned short)( nFirstVertex );
|
||||
pIndices[1] = (unsigned short)( nFirstVertex + i + 1 );
|
||||
pIndices[2] = (unsigned short)( nFirstVertex + i + 2 );
|
||||
pIndices += 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GenerateLineStripIndexBuffer( unsigned short* pIndices, int nIndexCount, int nFirstVertex )
|
||||
{
|
||||
if ( !pIndices )
|
||||
return;
|
||||
|
||||
int i;
|
||||
int numLines = nIndexCount / 2;
|
||||
for ( i = 0; i < numLines; ++i)
|
||||
{
|
||||
pIndices[0] = (unsigned short)( nFirstVertex + i );
|
||||
pIndices[1] = (unsigned short)( nFirstVertex + i + 1 );
|
||||
pIndices += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateLineLoopIndexBuffer( unsigned short* pIndices, int nIndexCount, int nFirstVertex )
|
||||
{
|
||||
if ( !pIndices )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
int numLines = nIndexCount / 2;
|
||||
|
||||
pIndices[0] = (unsigned short)( nFirstVertex + numLines - 1 );
|
||||
pIndices[1] = (unsigned short)( nFirstVertex );
|
||||
pIndices += 2;
|
||||
|
||||
for ( i = 1; i < numLines; ++i)
|
||||
{
|
||||
pIndices[0] = (unsigned short)( nFirstVertex + i - 1 );
|
||||
pIndices[1] = (unsigned short)( nFirstVertex + i );
|
||||
pIndices += 2;
|
||||
}
|
||||
}
|
138
tier2/p4helpers.cpp
Normal file
138
tier2/p4helpers.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "p4helpers.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "p4lib/ip4.h"
|
||||
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
#include <Windows.h>
|
||||
#endif // PLATFORM_WINDOWS_PC
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CP4File implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CP4File::CP4File( char const *szFilename )
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS_PC
|
||||
|
||||
// On windows, get the pathname of the file on disk first before using that as a perforce path
|
||||
// this avoids invalid Adds(). Have to go through GetShortPathName and then GetLongPathName from
|
||||
// the short path name
|
||||
|
||||
TCHAR szShortPathName[ MAX_PATH ] = TEXT( "" );
|
||||
const DWORD shortRetVal = GetShortPathName( szFilename, szShortPathName, ARRAYSIZE( szShortPathName ) );
|
||||
|
||||
if ( shortRetVal > 0 && shortRetVal <= ARRAYSIZE( szShortPathName ) )
|
||||
{
|
||||
TCHAR szLongPathName[ MAX_PATH ] = TEXT( "" );
|
||||
|
||||
const DWORD longRetVal = GetLongPathName( szShortPathName, szLongPathName, ARRAYSIZE( szLongPathName ) );
|
||||
|
||||
if ( longRetVal > 0 && longRetVal <= ARRAYSIZE( szLongPathName ) )
|
||||
{
|
||||
m_sFilename = szLongPathName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PLATFORM_WINDOWS_PC
|
||||
|
||||
m_sFilename = szFilename;
|
||||
}
|
||||
|
||||
CP4File::~CP4File()
|
||||
{
|
||||
}
|
||||
|
||||
bool CP4File::Edit( void )
|
||||
{
|
||||
if ( !p4 )
|
||||
return true;
|
||||
|
||||
return p4->OpenFileForEdit( m_sFilename.String() );
|
||||
}
|
||||
|
||||
bool CP4File::Add( void )
|
||||
{
|
||||
if ( !p4 )
|
||||
return true;
|
||||
|
||||
return p4->OpenFileForAdd( m_sFilename.String() );
|
||||
}
|
||||
|
||||
bool CP4File::Revert( void )
|
||||
{
|
||||
if ( !p4 )
|
||||
return true;
|
||||
|
||||
return p4->RevertFile( m_sFilename.String() );
|
||||
}
|
||||
|
||||
// Is the file in perforce?
|
||||
bool CP4File::IsFileInPerforce()
|
||||
{
|
||||
if ( !p4 )
|
||||
return false;
|
||||
|
||||
return p4->IsFileInPerforce( m_sFilename.String() );
|
||||
}
|
||||
|
||||
bool CP4File::SetFileType(const CUtlString& desiredFileType)
|
||||
{
|
||||
if ( !p4 )
|
||||
return false;
|
||||
|
||||
return p4->SetFileType( m_sFilename.String(), desiredFileType.String() );
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// CP4Factory implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
CP4Factory::CP4Factory()
|
||||
{
|
||||
}
|
||||
|
||||
CP4Factory::~CP4Factory()
|
||||
{
|
||||
}
|
||||
|
||||
bool CP4Factory::SetDummyMode( bool bDummyMode )
|
||||
{
|
||||
bool bOld = m_bDummyMode;
|
||||
m_bDummyMode = bDummyMode;
|
||||
return bOld;
|
||||
}
|
||||
|
||||
void CP4Factory::SetOpenFileChangeList( const char *szChangeListName )
|
||||
{
|
||||
if ( !m_bDummyMode && p4 )
|
||||
p4->SetOpenFileChangeList( szChangeListName );
|
||||
}
|
||||
|
||||
CP4File *CP4Factory::AccessFile( char const *szFilename ) const
|
||||
{
|
||||
if ( !m_bDummyMode )
|
||||
return new CP4File( szFilename );
|
||||
else
|
||||
return new CP4File_Dummy( szFilename );
|
||||
}
|
||||
|
||||
|
||||
// Default p4 factory
|
||||
static CP4Factory s_static_p4_factory;
|
||||
CP4Factory *g_p4factory = &s_static_p4_factory; // NULL before the factory constructs
|
||||
|
916
tier2/renderutils.cpp
Normal file
916
tier2/renderutils.cpp
Normal file
@ -0,0 +1,916 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A set of utilities to render standard shapes
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/renderutils.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imesh.h"
|
||||
#include "materialsystem/imaterial.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "tier0/basetypes.h"
|
||||
#include "togl/rendermechanism.h"
|
||||
|
||||
#if !defined(M_PI)
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Globals
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool s_bMaterialsInitialized = false;
|
||||
static IMaterial *s_pWireframe;
|
||||
static IMaterial *s_pWireframeIgnoreZ;
|
||||
static IMaterial *s_pVertexColor;
|
||||
static IMaterial *s_pVertexColorIgnoreZ;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initializes standard materials
|
||||
//-----------------------------------------------------------------------------
|
||||
void InitializeStandardMaterials()
|
||||
{
|
||||
if ( s_bMaterialsInitialized )
|
||||
return;
|
||||
|
||||
s_bMaterialsInitialized = true;
|
||||
|
||||
KeyValues *pVMTKeyValues = new KeyValues( "wireframe" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
s_pWireframe = g_pMaterialSystem->CreateMaterial( "__utilWireframe", pVMTKeyValues );
|
||||
|
||||
pVMTKeyValues = new KeyValues( "wireframe" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
|
||||
pVMTKeyValues->SetInt( "$ignorez", 1 );
|
||||
s_pWireframeIgnoreZ = g_pMaterialSystem->CreateMaterial( "__utilWireframeIgnoreZ", pVMTKeyValues );
|
||||
|
||||
pVMTKeyValues = new KeyValues( "unlitgeneric" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
|
||||
s_pVertexColor = g_pMaterialSystem->CreateMaterial( "__utilVertexColor", pVMTKeyValues );
|
||||
|
||||
pVMTKeyValues = new KeyValues( "unlitgeneric" );
|
||||
pVMTKeyValues->SetInt( "$vertexcolor", 1 );
|
||||
pVMTKeyValues->SetInt( "$vertexalpha", 1 );
|
||||
pVMTKeyValues->SetInt( "$ignorez", 1 );
|
||||
s_pVertexColorIgnoreZ = g_pMaterialSystem->CreateMaterial( "__utilVertexColorIgnoreZ", pVMTKeyValues );
|
||||
}
|
||||
|
||||
void ShutdownStandardMaterials()
|
||||
{
|
||||
if ( !s_bMaterialsInitialized )
|
||||
return;
|
||||
|
||||
s_bMaterialsInitialized = false;
|
||||
|
||||
s_pWireframe->DecrementReferenceCount();
|
||||
s_pWireframe = NULL;
|
||||
|
||||
s_pWireframeIgnoreZ->DecrementReferenceCount();
|
||||
s_pWireframeIgnoreZ = NULL;
|
||||
|
||||
s_pVertexColor->DecrementReferenceCount();
|
||||
s_pVertexColor = NULL;
|
||||
|
||||
s_pVertexColorIgnoreZ->DecrementReferenceCount();
|
||||
s_pVertexColorIgnoreZ = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders a wireframe sphere
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderWireframeSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
// Make one more coordinate because (u,v) is discontinuous.
|
||||
++nTheta;
|
||||
|
||||
int nVertices = nPhi * nTheta;
|
||||
int nIndices = ( nTheta - 1 ) * 4 * ( nPhi - 1 );
|
||||
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
IMesh* pMesh = pRenderContext->GetDynamicMesh();
|
||||
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, nVertices, nIndices );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
int i, j;
|
||||
for ( i = 0; i < nPhi; ++i )
|
||||
{
|
||||
for ( j = 0; j < nTheta; ++j )
|
||||
{
|
||||
float u = j / ( float )( nTheta - 1 );
|
||||
float v = i / ( float )( nPhi - 1 );
|
||||
float theta = 2.0f * M_PI * u;
|
||||
float phi = M_PI * v;
|
||||
|
||||
meshBuilder.Position3f( vCenter.x + ( flRadius * sin(phi) * cos(theta) ),
|
||||
vCenter.y + ( flRadius * sin(phi) * sin(theta) ),
|
||||
vCenter.z + ( flRadius * cos(phi) ) );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
for ( i = 0; i < nPhi - 1; ++i )
|
||||
{
|
||||
for ( j = 0; j < nTheta - 1; ++j )
|
||||
{
|
||||
int idx = nTheta * i + j;
|
||||
|
||||
meshBuilder.Index( idx );
|
||||
meshBuilder.AdvanceIndex();
|
||||
|
||||
meshBuilder.Index( idx + nTheta );
|
||||
meshBuilder.AdvanceIndex();
|
||||
|
||||
meshBuilder.Index( idx );
|
||||
meshBuilder.AdvanceIndex();
|
||||
|
||||
meshBuilder.Index( idx + 1 );
|
||||
meshBuilder.AdvanceIndex();
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Draws a sphere
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, IMaterial *pMaterial )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
// Two extra degenerate triangles per row (except the last one)
|
||||
int nTriangles = 2 * nTheta * ( nPhi - 1 );
|
||||
int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
|
||||
if ( nTriangles == 0 )
|
||||
return;
|
||||
|
||||
pRenderContext->Bind( pMaterial );
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
|
||||
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nTriangles, nIndices );
|
||||
|
||||
// Build the index buffer.
|
||||
float flOONPhi = 1.0f / (nPhi-1);
|
||||
float flOONTheta = 1.0f / (nTheta-1);
|
||||
|
||||
int i, j;
|
||||
for ( i = 0; i < nPhi; ++i )
|
||||
{
|
||||
for ( j = 0; j < nTheta; ++j )
|
||||
{
|
||||
float u = j / ( float )( nTheta - 1 );
|
||||
float v = i / ( float )( nPhi - 1 );
|
||||
float theta = 2.0f * M_PI * u;
|
||||
float phi = M_PI * v;
|
||||
|
||||
Vector vecPos;
|
||||
vecPos.x = flRadius * sin(phi) * cos(theta);
|
||||
vecPos.y = flRadius * sin(phi) * sin(theta);
|
||||
vecPos.z = flRadius * cos(phi);
|
||||
|
||||
Vector vecNormal = vecPos;
|
||||
VectorNormalize(vecNormal);
|
||||
|
||||
vecPos += vCenter;
|
||||
|
||||
meshBuilder.Position3f( vecPos.x, vecPos.y, vecPos.z );
|
||||
meshBuilder.Normal3f( vecNormal.x, vecNormal.y, vecNormal.z );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.TexCoord2f( 0, j * flOONTheta, i * flOONPhi );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the triangle strips.
|
||||
int idx = 0;
|
||||
for ( i = 0; i < nPhi - 1; ++i )
|
||||
{
|
||||
for ( j = 0; j < nTheta; ++j )
|
||||
{
|
||||
idx = nTheta * i + j;
|
||||
|
||||
meshBuilder.Index( idx + nTheta );
|
||||
meshBuilder.AdvanceIndex();
|
||||
|
||||
meshBuilder.Index( idx );
|
||||
meshBuilder.AdvanceIndex();
|
||||
}
|
||||
|
||||
// Emit a degenerate triangle to skip to the next row without a connecting triangle
|
||||
if ( i < nPhi - 2 )
|
||||
{
|
||||
meshBuilder.Index( idx );
|
||||
meshBuilder.AdvanceIndex();
|
||||
|
||||
meshBuilder.Index( idx + nTheta + 1 );
|
||||
meshBuilder.AdvanceIndex();
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
void RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi, Color c, bool bZBuffer )
|
||||
{
|
||||
IMaterial *pMaterial = bZBuffer ? s_pVertexColor : s_pVertexColorIgnoreZ;
|
||||
Color cActual( c.r(), c.g(), c.b(), c.a() );
|
||||
RenderSphere( vCenter, flRadius, nTheta, nPhi, cActual, pMaterial );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Box vertices
|
||||
//-----------------------------------------------------------------------------
|
||||
static int s_pBoxFaceIndices[6][4] =
|
||||
{
|
||||
{ 0, 4, 6, 2 }, // -x
|
||||
{ 5, 1, 3, 7 }, // +x
|
||||
{ 0, 1, 5, 4 }, // -y
|
||||
{ 2, 6, 7, 3 }, // +y
|
||||
{ 0, 2, 3, 1 }, // -z
|
||||
{ 4, 5, 7, 6 } // +z
|
||||
};
|
||||
|
||||
static int s_pBoxFaceIndicesInsideOut[6][4] =
|
||||
{
|
||||
{ 0, 2, 6, 4 }, // -x
|
||||
{ 5, 7, 3, 1 }, // +x
|
||||
{ 0, 4, 5, 1 }, // -y
|
||||
{ 2, 3, 7, 6 }, // +y
|
||||
{ 0, 1, 3, 2 }, // -z
|
||||
{ 4, 6, 7, 5 } // +z
|
||||
};
|
||||
|
||||
static void GenerateBoxVertices( const Vector &vOrigin, const QAngle& angles, const Vector &vMins, const Vector &vMaxs, Vector pVerts[8] )
|
||||
{
|
||||
// Build a rotation matrix from orientation
|
||||
matrix3x4_t fRotateMatrix;
|
||||
AngleMatrix( angles, fRotateMatrix );
|
||||
|
||||
Vector vecPos;
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
vecPos[0] = ( i & 0x1 ) ? vMaxs[0] : vMins[0];
|
||||
vecPos[1] = ( i & 0x2 ) ? vMaxs[1] : vMins[1];
|
||||
vecPos[2] = ( i & 0x4 ) ? vMaxs[2] : vMins[2];
|
||||
|
||||
VectorRotate( vecPos, fRotateMatrix, pVerts[i] );
|
||||
pVerts[i] += vOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders a wireframe box relative to an origin
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderWireframeBox( const Vector &vOrigin, const QAngle& angles, const Vector &vMins, const Vector &vMaxs, Color c, bool bZBuffer )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
|
||||
Vector p[8];
|
||||
GenerateBoxVertices( vOrigin, angles, vMins, vMaxs, p );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, 24 );
|
||||
|
||||
// Draw the box
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
int *pFaceIndex = s_pBoxFaceIndices[i];
|
||||
|
||||
for ( int j = 0; j < 4; ++j )
|
||||
{
|
||||
meshBuilder.Position3fv( p[pFaceIndex[j]].Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( p[pFaceIndex[ (j == 3) ? 0 : j+1 ] ].Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders a solid box
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderBox( const Vector& vOrigin, const QAngle& angles, const Vector& vMins, const Vector& vMaxs, Color c, IMaterial *pMaterial, bool bInsideOut )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
pRenderContext->Bind( pMaterial );
|
||||
|
||||
Vector p[8];
|
||||
GenerateBoxVertices( vOrigin, angles, vMins, vMaxs, p );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 12 );
|
||||
|
||||
// Draw the box
|
||||
Vector vecNormal;
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
vecNormal.Init();
|
||||
vecNormal[ i/2 ] = ( i & 0x1 ) ? 1.0f : -1.0f;
|
||||
|
||||
int *ppFaceIndices = bInsideOut ? s_pBoxFaceIndicesInsideOut[i] : s_pBoxFaceIndices[i];
|
||||
for ( int j = 1; j < 3; ++j )
|
||||
{
|
||||
int i0 = ppFaceIndices[0];
|
||||
int i1 = ppFaceIndices[j];
|
||||
int i2 = ppFaceIndices[j+1];
|
||||
|
||||
meshBuilder.Position3fv( p[i0].Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( p[i2].Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, 1.0f, ( j == 1 ) ? 1.0f : 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( p[i1].Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, ( j == 1 ) ? 0.0f : 1.0f, 1.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
void RenderBox( const Vector& vOrigin, const QAngle& angles, const Vector& vMins, const Vector& vMaxs, Color c, bool bZBuffer, bool bInsideOut )
|
||||
{
|
||||
IMaterial *pMaterial = bZBuffer ? s_pVertexColor : s_pVertexColorIgnoreZ;
|
||||
Color cActual( c.r(), c.g(), c.b(), c.a() );
|
||||
RenderBox( vOrigin, angles, vMins, vMaxs, cActual, pMaterial, bInsideOut );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders axes, red->x, green->y, blue->z
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderAxes( const Vector &vOrigin, float flScale, bool bZBuffer )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 255, 0, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x + flScale, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 255, 0, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 0, 255, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y + flScale, vOrigin.z );
|
||||
meshBuilder.Color4ub( 0, 255, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 0, 0, 255, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z + flScale );
|
||||
meshBuilder.Color4ub( 0, 0, 255, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
void RenderAxes( const matrix3x4_t &transform, float flScale, bool bZBuffer )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
Vector xAxis, yAxis, zAxis, vOrigin, temp;
|
||||
MatrixGetColumn( transform, 0, xAxis );
|
||||
MatrixGetColumn( transform, 1, yAxis );
|
||||
MatrixGetColumn( transform, 2, zAxis );
|
||||
MatrixGetColumn( transform, 3, vOrigin );
|
||||
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
|
||||
|
||||
meshBuilder.Position3fv( vOrigin.Base() );
|
||||
meshBuilder.Color4ub( 255, 0, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorMA( vOrigin, flScale, xAxis, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( 255, 0, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 0, 255, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorMA( vOrigin, flScale, yAxis, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( 0, 255, 0, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3f( vOrigin.x, vOrigin.y, vOrigin.z );
|
||||
meshBuilder.Color4ub( 0, 0, 255, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorMA( vOrigin, flScale, zAxis, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( 0, 0, 255, 255 );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Render a line
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderLine( const Vector& v1, const Vector& v2, Color c, bool bZBuffer )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 );
|
||||
|
||||
meshBuilder.Position3fv( v1.Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( v2.Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Draws a triangle
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderTriangle( const Vector& p1, const Vector& p2, const Vector& p3, Color c, IMaterial *pMaterial )
|
||||
{
|
||||
InitializeStandardMaterials();
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
pRenderContext->Bind( pMaterial );
|
||||
|
||||
unsigned char chRed = c.r();
|
||||
unsigned char chGreen = c.g();
|
||||
unsigned char chBlue = c.b();
|
||||
unsigned char chAlpha = c.a();
|
||||
|
||||
Vector vecNormal;
|
||||
Vector vecDelta1, vecDelta2;
|
||||
VectorSubtract( p2, p1, vecDelta1 );
|
||||
VectorSubtract( p3, p1, vecDelta2 );
|
||||
CrossProduct( vecDelta1, vecDelta2, vecNormal );
|
||||
VectorNormalize( vecNormal );
|
||||
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 1 );
|
||||
|
||||
meshBuilder.Position3fv( p1.Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( p2.Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( p3.Base() );
|
||||
meshBuilder.Color4ub( chRed, chGreen, chBlue, chAlpha );
|
||||
meshBuilder.Normal3fv( vecNormal.Base() );
|
||||
meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
void RenderTriangle( const Vector& p1, const Vector& p2, const Vector& p3, Color c, bool bZBuffer )
|
||||
{
|
||||
IMaterial *pMaterial = bZBuffer ? s_pVertexColor : s_pVertexColorIgnoreZ;
|
||||
Color cActual( c.r(), c.g(), c.b(), c.a() );
|
||||
RenderTriangle( p1, p2, p3, cActual, pMaterial );
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders an extruded box
|
||||
//-----------------------------------------------------------------------------
|
||||
static void DrawAxes( const Vector& origin, Vector* pts, int idx, Color c, CMeshBuilder& meshBuilder )
|
||||
{
|
||||
Vector start, temp;
|
||||
VectorAdd( pts[idx], origin, start );
|
||||
meshBuilder.Position3fv( start.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
int endidx = (idx & 0x1) ? idx - 1 : idx + 1;
|
||||
VectorAdd( pts[endidx], origin, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( start.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
endidx = (idx & 0x2) ? idx - 2 : idx + 2;
|
||||
VectorAdd( pts[endidx], origin, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( start.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
endidx = (idx & 0x4) ? idx - 4 : idx + 4;
|
||||
VectorAdd( pts[endidx], origin, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
|
||||
static void DrawExtrusionFace( const Vector& start, const Vector& end,
|
||||
Vector* pts, int idx1, int idx2, Color c, CMeshBuilder& meshBuilder )
|
||||
{
|
||||
Vector temp;
|
||||
VectorAdd( pts[idx1], start, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorAdd( pts[idx2], start, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorAdd( pts[idx2], end, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorAdd( pts[idx1], end, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
VectorAdd( pts[idx1], start, temp );
|
||||
meshBuilder.Position3fv( temp.Base() );
|
||||
meshBuilder.Color4ub( c.r(), c.g(), c.b(), c.a() );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
|
||||
void RenderWireframeSweptBox( const Vector &vStart, const Vector &vEnd, const QAngle &angles, const Vector &vMins, const Vector &vMaxs, Color c, bool bZBuffer )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
pRenderContext->Bind( bZBuffer ? s_pWireframe : s_pWireframeIgnoreZ );
|
||||
|
||||
Color cActual( c.r(), c.g(), c.b(), c.a() );
|
||||
|
||||
// Build a rotation matrix from angles
|
||||
matrix3x4_t fRotateMatrix;
|
||||
AngleMatrix( angles, fRotateMatrix );
|
||||
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( );
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_LINES, 30 );
|
||||
|
||||
Vector vDelta;
|
||||
VectorSubtract( vEnd, vStart, vDelta );
|
||||
|
||||
// Compute the box points, rotated but without the origin added
|
||||
Vector temp;
|
||||
Vector pts[8];
|
||||
float dot[8];
|
||||
int minidx = 0;
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
temp.x = (i & 0x1) ? vMaxs[0] : vMins[0];
|
||||
temp.y = (i & 0x2) ? vMaxs[1] : vMins[1];
|
||||
temp.z = (i & 0x4) ? vMaxs[2] : vMins[2];
|
||||
|
||||
// Rotate the corner point
|
||||
VectorRotate( temp, fRotateMatrix, pts[i] );
|
||||
|
||||
// Find the dot product with dir
|
||||
dot[i] = DotProduct( pts[i], vDelta );
|
||||
if ( dot[i] < dot[minidx] )
|
||||
{
|
||||
minidx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Choose opposite corner
|
||||
int maxidx = minidx ^ 0x7;
|
||||
|
||||
// Draw the start + end axes...
|
||||
DrawAxes( vStart, pts, minidx, cActual, meshBuilder );
|
||||
DrawAxes( vEnd, pts, maxidx, cActual, meshBuilder );
|
||||
|
||||
// Draw the extrusion faces
|
||||
for (int j = 0; j < 3; ++j )
|
||||
{
|
||||
int dirflag1 = ( 1 << ((j+1)%3) );
|
||||
int dirflag2 = ( 1 << ((j+2)%3) );
|
||||
|
||||
int idx1, idx2, idx3;
|
||||
idx1 = (minidx & dirflag1) ? minidx - dirflag1 : minidx + dirflag1;
|
||||
idx2 = (minidx & dirflag2) ? minidx - dirflag2 : minidx + dirflag2;
|
||||
idx3 = (minidx & dirflag2) ? idx1 - dirflag2 : idx1 + dirflag2;
|
||||
|
||||
DrawExtrusionFace( vStart, vEnd, pts, idx1, idx3, cActual, meshBuilder );
|
||||
DrawExtrusionFace( vStart, vEnd, pts, idx2, idx3, cActual, meshBuilder );
|
||||
}
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Draws a axis-aligned quad
|
||||
//-----------------------------------------------------------------------------
|
||||
void RenderQuad( IMaterial *pMaterial, float x, float y, float w, float h,
|
||||
float z, float s0, float t0, float s1, float t1, const Color& clr )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
|
||||
|
||||
meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a());
|
||||
meshBuilder.TexCoord2f( 0, s0, t0 );
|
||||
meshBuilder.Position3f( x, y, z );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a());
|
||||
meshBuilder.TexCoord2f( 0, s1, t0 );
|
||||
meshBuilder.Position3f( x + w, y, z );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a());
|
||||
meshBuilder.TexCoord2f( 0, s1, t1 );
|
||||
meshBuilder.Position3f( x + w, y + h, z );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a());
|
||||
meshBuilder.TexCoord2f( 0, s0, t1 );
|
||||
meshBuilder.Position3f( x, y + h, z );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
meshBuilder.End();
|
||||
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Renders a screen space quad
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void DrawScreenSpaceRectangle( IMaterial *pMaterial,
|
||||
int nDestX, int nDestY, int nWidth, int nHeight, // Rect to draw into in screen space
|
||||
float flSrcTextureX0, float flSrcTextureY0, // which texel you want to appear at destx/y
|
||||
float flSrcTextureX1, float flSrcTextureY1, // which texel you want to appear at destx+width-1, desty+height-1
|
||||
int nSrcTextureWidth, int nSrcTextureHeight, // needed for fixup
|
||||
void *pClientRenderable, // Used to pass to the bind proxies
|
||||
int nXDice, int nYDice, // Amount to tessellate the mesh
|
||||
float fDepth ) // what Z value to put in the verts (def 0.0)
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
|
||||
|
||||
if ( ( nWidth <= 0 ) || ( nHeight <= 0 ) )
|
||||
return;
|
||||
|
||||
tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PushMatrix();
|
||||
pRenderContext->LoadIdentity();
|
||||
|
||||
pRenderContext->Bind( pMaterial, pClientRenderable );
|
||||
|
||||
int xSegments = max( nXDice, 1);
|
||||
int ySegments = max( nYDice, 1);
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
|
||||
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
|
||||
meshBuilder.Begin( pMesh, MATERIAL_QUADS, xSegments * ySegments );
|
||||
|
||||
int nScreenWidth, nScreenHeight;
|
||||
pRenderContext->GetRenderTargetDimensions( nScreenWidth, nScreenHeight );
|
||||
|
||||
float flOffset = 0.5f;
|
||||
|
||||
float flLeftX = nDestX - flOffset;
|
||||
float flRightX = nDestX + nWidth - flOffset;
|
||||
|
||||
float flTopY = nDestY - flOffset;
|
||||
float flBottomY = nDestY + nHeight - flOffset;
|
||||
|
||||
float flSubrectWidth = flSrcTextureX1 - flSrcTextureX0;
|
||||
float flSubrectHeight = flSrcTextureY1 - flSrcTextureY0;
|
||||
|
||||
float flTexelsPerPixelX = ( nWidth > 1 ) ? flSubrectWidth / ( nWidth - 1 ) : 0.0f;
|
||||
float flTexelsPerPixelY = ( nHeight > 1 ) ? flSubrectHeight / ( nHeight - 1 ) : 0.0f;
|
||||
|
||||
float flLeftU = flSrcTextureX0 + 0.5f - ( 0.5f * flTexelsPerPixelX );
|
||||
float flRightU = flSrcTextureX1 + 0.5f + ( 0.5f * flTexelsPerPixelX );
|
||||
float flTopV = flSrcTextureY0 + 0.5f - ( 0.5f * flTexelsPerPixelY );
|
||||
float flBottomV = flSrcTextureY1 + 0.5f + ( 0.5f * flTexelsPerPixelY );
|
||||
|
||||
float flOOTexWidth = 1.0f / nSrcTextureWidth;
|
||||
float flOOTexHeight = 1.0f / nSrcTextureHeight;
|
||||
flLeftU *= flOOTexWidth;
|
||||
flRightU *= flOOTexWidth;
|
||||
flTopV *= flOOTexHeight;
|
||||
flBottomV *= flOOTexHeight;
|
||||
|
||||
// Get the current viewport size
|
||||
int vx, vy, vw, vh;
|
||||
pRenderContext->GetViewport( vx, vy, vw, vh );
|
||||
|
||||
// map from screen pixel coords to -1..1
|
||||
flRightX = FLerp( -1, 1, 0, vw, flRightX );
|
||||
flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
|
||||
flTopY = FLerp( 1, -1, 0, vh ,flTopY );
|
||||
flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
|
||||
|
||||
// Dice the quad up...
|
||||
if ( ( xSegments > 1 ) || ( ySegments > 1 ) )
|
||||
{
|
||||
// Screen height and width of a subrect
|
||||
float flWidth = (flRightX - flLeftX) / (float) xSegments;
|
||||
float flHeight = (flTopY - flBottomY) / (float) ySegments;
|
||||
|
||||
// UV height and width of a subrect
|
||||
float flUWidth = (flRightU - flLeftU) / (float) xSegments;
|
||||
float flVHeight = (flBottomV - flTopV) / (float) ySegments;
|
||||
|
||||
for ( int x=0; x < xSegments; x++ )
|
||||
{
|
||||
for ( int y=0; y < ySegments; y++ )
|
||||
{
|
||||
// Top left
|
||||
meshBuilder.Position3f( flLeftX + (float) x * flWidth, flTopY - (float) y * flHeight, fDepth );
|
||||
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
|
||||
meshBuilder.TexCoord2f( 0, flLeftU + (float) x * flUWidth, flTopV + (float) y * flVHeight);
|
||||
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
|
||||
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
// Top right (x+1)
|
||||
meshBuilder.Position3f( flLeftX + (float) (x+1) * flWidth, flTopY - (float) y * flHeight, fDepth );
|
||||
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
|
||||
meshBuilder.TexCoord2f( 0, flLeftU + (float) (x+1) * flUWidth, flTopV + (float) y * flVHeight);
|
||||
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
|
||||
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
// Bottom right (x+1), (y+1)
|
||||
meshBuilder.Position3f( flLeftX + (float) (x+1) * flWidth, flTopY - (float) (y+1) * flHeight, fDepth );
|
||||
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
|
||||
meshBuilder.TexCoord2f( 0, flLeftU + (float) (x+1) * flUWidth, flTopV + (float)(y+1) * flVHeight);
|
||||
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
|
||||
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
|
||||
// Bottom left (y+1)
|
||||
meshBuilder.Position3f( flLeftX + (float) x * flWidth, flTopY - (float) (y+1) * flHeight, fDepth );
|
||||
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
|
||||
meshBuilder.TexCoord2f( 0, flLeftU + (float) x * flUWidth, flTopV + (float)(y+1) * flVHeight);
|
||||
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
|
||||
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
else // just one quad
|
||||
{
|
||||
for ( int corner=0; corner<4; corner++ )
|
||||
{
|
||||
bool bLeft = (corner==0) || (corner==3);
|
||||
meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, fDepth );
|
||||
meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
|
||||
meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
|
||||
meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
|
||||
meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
|
||||
meshBuilder.AdvanceVertex();
|
||||
}
|
||||
}
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_VIEW );
|
||||
pRenderContext->PopMatrix();
|
||||
|
||||
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
|
||||
pRenderContext->PopMatrix();
|
||||
}
|
506
tier2/riff.cpp
Normal file
506
tier2/riff.cpp
Normal file
@ -0,0 +1,506 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// Avoid these warnings:
|
||||
#pragma warning(disable : 4512) // warning C4512: 'InFileRIFF' : assignment operator could not be generated
|
||||
#pragma warning(disable : 4514) // warning C4514: 'RIFFName' : unreferenced inline function has been removed
|
||||
|
||||
#include "riff.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
#if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Test code that implements the interface on stdio
|
||||
//-----------------------------------------------------------------------------
|
||||
class StdIOReadBinary : public IFileReadBinary
|
||||
{
|
||||
public:
|
||||
int open( const char *pFileName )
|
||||
{
|
||||
return (int)fopen( pFileName, "rb" );
|
||||
}
|
||||
|
||||
int read( void *pOutput, int size, int file )
|
||||
{
|
||||
FILE *fp = (FILE *)file;
|
||||
|
||||
return fread( pOutput, size, 1, fp );
|
||||
}
|
||||
|
||||
void seek( int file, int pos )
|
||||
{
|
||||
fseek( (FILE *)file, pos, SEEK_SET );
|
||||
}
|
||||
|
||||
unsigned int tell( int file )
|
||||
{
|
||||
return ftell( (FILE *)file );
|
||||
}
|
||||
|
||||
unsigned int size( int file )
|
||||
{
|
||||
FILE *fp = (FILE *)file;
|
||||
if ( !fp )
|
||||
return 0;
|
||||
|
||||
unsigned int pos = ftell( fp );
|
||||
fseek( fp, 0, SEEK_END );
|
||||
unsigned int size = ftell( fp );
|
||||
|
||||
fseek( fp, pos, SEEK_SET );
|
||||
return size;
|
||||
}
|
||||
|
||||
void close( int file )
|
||||
{
|
||||
FILE *fp = (FILE *)file;
|
||||
|
||||
fclose( fp );
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#define RIFF_ID MAKEID('R','I','F','F')
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Opens a RIFF file using the given I/O mechanism
|
||||
// Input : *pFileName
|
||||
// &io - I/O interface
|
||||
//-----------------------------------------------------------------------------
|
||||
InFileRIFF::InFileRIFF( const char *pFileName, IFileReadBinary &io ) : m_io(io)
|
||||
{
|
||||
m_file = m_io.open( pFileName );
|
||||
|
||||
int riff = 0;
|
||||
if ( !m_file )
|
||||
{
|
||||
m_riffSize = 0;
|
||||
m_riffName = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
riff = ReadInt();
|
||||
if ( riff != RIFF_ID )
|
||||
{
|
||||
printf( "Not a RIFF File [%s]\n", pFileName );
|
||||
m_riffSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we store size as size of all chunks
|
||||
// subtract off the RIFF form type (e.g. 'WAVE', 4 bytes)
|
||||
m_riffSize = ReadInt() - 4;
|
||||
m_riffName = ReadInt();
|
||||
|
||||
// HACKHACK: LWV files don't obey the RIFF format!!!
|
||||
// Do this or miss the linguistic chunks at the end. Lame!
|
||||
// subtract off 12 bytes for (RIFF, size, WAVE)
|
||||
m_riffSize = m_io.size( m_file ) - 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Close the file
|
||||
//-----------------------------------------------------------------------------
|
||||
InFileRIFF::~InFileRIFF( void )
|
||||
{
|
||||
m_io.close( m_file );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: read a 4-byte int out of the stream
|
||||
// Output : int = read value, default is zero
|
||||
//-----------------------------------------------------------------------------
|
||||
int InFileRIFF::ReadInt( void )
|
||||
{
|
||||
int tmp = 0;
|
||||
m_io.read( &tmp, sizeof(int), m_file );
|
||||
tmp = LittleLong( tmp );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Read a block of binary data
|
||||
// Input : *pOutput - pointer to destination memory
|
||||
// dataSize - size of block to read
|
||||
// Output : int - number of bytes read
|
||||
//-----------------------------------------------------------------------------
|
||||
int InFileRIFF::ReadData( void *pOutput, int dataSize )
|
||||
{
|
||||
int count = m_io.read( pOutput, dataSize, m_file );
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets the file position
|
||||
// Output : int (bytes from start of file)
|
||||
//-----------------------------------------------------------------------------
|
||||
int InFileRIFF::PositionGet( void )
|
||||
{
|
||||
return m_io.tell( m_file );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Seek to file position
|
||||
// Input : position - bytes from start of file
|
||||
//-----------------------------------------------------------------------------
|
||||
void InFileRIFF::PositionSet( int position )
|
||||
{
|
||||
m_io.seek( m_file, position );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Used to write a RIFF format file
|
||||
//-----------------------------------------------------------------------------
|
||||
OutFileRIFF::OutFileRIFF( const char *pFileName, IFileWriteBinary &io ) : m_io( io )
|
||||
{
|
||||
m_file = m_io.create( pFileName );
|
||||
|
||||
if ( !m_file )
|
||||
return;
|
||||
|
||||
int riff = RIFF_ID;
|
||||
m_io.write( &riff, 4, m_file );
|
||||
|
||||
m_riffSize = 0;
|
||||
m_nNamePos = m_io.tell( m_file );
|
||||
|
||||
// Save room for the size and name now
|
||||
WriteInt( 0 );
|
||||
|
||||
// Write out the name
|
||||
WriteInt( RIFF_WAVE );
|
||||
|
||||
m_bUseIncorrectLISETLength = false;
|
||||
m_nLISETSize = 0;
|
||||
}
|
||||
|
||||
OutFileRIFF::~OutFileRIFF( void )
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return;
|
||||
|
||||
unsigned int size = m_io.tell( m_file ) -8;
|
||||
m_io.seek( m_file, m_nNamePos );
|
||||
|
||||
if ( m_bUseIncorrectLISETLength )
|
||||
{
|
||||
size = m_nLISETSize - 8;
|
||||
}
|
||||
|
||||
WriteInt( size );
|
||||
m_io.close( m_file );
|
||||
}
|
||||
|
||||
void OutFileRIFF::HasLISETData( int position )
|
||||
{
|
||||
m_bUseIncorrectLISETLength = true;
|
||||
m_nLISETSize = position;
|
||||
}
|
||||
|
||||
bool OutFileRIFF::WriteInt( int number )
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return false;
|
||||
|
||||
m_io.write( &number, sizeof( int ), m_file );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OutFileRIFF::WriteData( void *pOutput, int dataSize )
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return false;
|
||||
|
||||
m_io.write( pOutput, dataSize, m_file );
|
||||
return true;
|
||||
}
|
||||
|
||||
int OutFileRIFF::PositionGet( void )
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return 0;
|
||||
|
||||
return m_io.tell( m_file );
|
||||
}
|
||||
|
||||
void OutFileRIFF::PositionSet( int position )
|
||||
{
|
||||
if ( !IsValid() )
|
||||
return;
|
||||
|
||||
m_io.seek( m_file, position );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create an iterator for the given file
|
||||
// Input : &riff - riff file
|
||||
// size - size of file or sub-chunk
|
||||
//-----------------------------------------------------------------------------
|
||||
IterateRIFF::IterateRIFF( InFileRIFF &riff, int size )
|
||||
: m_riff(riff), m_size(size)
|
||||
{
|
||||
if ( !m_riff.RIFFSize() )
|
||||
{
|
||||
// bad file, just be an empty iterator
|
||||
ChunkClear();
|
||||
return;
|
||||
}
|
||||
|
||||
// get the position and parse a chunk
|
||||
m_start = riff.PositionGet();
|
||||
ChunkSetup();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set up a sub-chunk iterator
|
||||
// Input : &parent - parent iterator
|
||||
//-----------------------------------------------------------------------------
|
||||
IterateRIFF::IterateRIFF( IterateRIFF &parent )
|
||||
: m_riff(parent.m_riff), m_size(parent.ChunkSize())
|
||||
{
|
||||
m_start = parent.ChunkFilePosition();
|
||||
ChunkSetup();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parse the chunk at the current file position
|
||||
// This object will iterate over the sub-chunks of this chunk.
|
||||
// This makes for easy hierarchical parsing
|
||||
//-----------------------------------------------------------------------------
|
||||
void IterateRIFF::ChunkSetup( void )
|
||||
{
|
||||
m_chunkPosition = m_riff.PositionGet();
|
||||
|
||||
m_chunkName = m_riff.ReadInt();
|
||||
m_chunkSize = m_riff.ReadInt();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: clear chunk setup, ChunkAvailable will return false
|
||||
//-----------------------------------------------------------------------------
|
||||
void IterateRIFF::ChunkClear( void )
|
||||
{
|
||||
m_chunkSize = -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If there are chunks left to read beyond this one, return true
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IterateRIFF::ChunkAvailable( void )
|
||||
{
|
||||
if ( m_chunkSize != -1 && m_chunkSize < 0x10000000 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Go to the next chunk in the file, return true if there is one.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool IterateRIFF::ChunkNext( void )
|
||||
{
|
||||
if ( !ChunkAvailable() )
|
||||
return false;
|
||||
|
||||
int nextPos = m_chunkPosition + 8 + m_chunkSize;
|
||||
|
||||
// chunks are aligned
|
||||
nextPos += m_chunkSize & 1;
|
||||
|
||||
if ( nextPos >= (m_start + m_size) )
|
||||
{
|
||||
ChunkClear();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_riff.PositionSet( nextPos );
|
||||
|
||||
ChunkSetup();
|
||||
return ChunkAvailable();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get the chunk FOURCC as an int
|
||||
// Output : unsigned int
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int IterateRIFF::ChunkName( void )
|
||||
{
|
||||
return m_chunkName;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: get the size of this chunk
|
||||
// Output : unsigned int
|
||||
//-----------------------------------------------------------------------------
|
||||
unsigned int IterateRIFF::ChunkSize( void )
|
||||
{
|
||||
return m_chunkSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Read the entire chunk into a buffer
|
||||
// Input : *pOutput - dest buffer
|
||||
// Output : int bytes read
|
||||
//-----------------------------------------------------------------------------
|
||||
int IterateRIFF::ChunkRead( void *pOutput )
|
||||
{
|
||||
return m_riff.ReadData( pOutput, ChunkSize() );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Read a partial chunk (updates file position for subsequent partial reads).
|
||||
// Input : *pOutput - dest buffer
|
||||
// dataSize - partial size
|
||||
// Output : int - bytes read
|
||||
//-----------------------------------------------------------------------------
|
||||
int IterateRIFF::ChunkReadPartial( void *pOutput, int dataSize )
|
||||
{
|
||||
return m_riff.ReadData( pOutput, dataSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Read a 4-byte int
|
||||
// Output : int - read int
|
||||
//-----------------------------------------------------------------------------
|
||||
int IterateRIFF::ChunkReadInt( void )
|
||||
{
|
||||
return m_riff.ReadInt();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Used to iterate over an InFileRIFF
|
||||
//-----------------------------------------------------------------------------
|
||||
IterateOutputRIFF::IterateOutputRIFF( OutFileRIFF &riff )
|
||||
: m_riff( riff )
|
||||
{
|
||||
if ( !m_riff.IsValid() )
|
||||
return;
|
||||
|
||||
m_start = m_riff.PositionGet();
|
||||
m_chunkPosition = m_start;
|
||||
m_chunkStart = -1;
|
||||
}
|
||||
|
||||
IterateOutputRIFF::IterateOutputRIFF( IterateOutputRIFF &parent )
|
||||
: m_riff(parent.m_riff)
|
||||
{
|
||||
m_start = parent.ChunkFilePosition();
|
||||
m_chunkPosition = m_start;
|
||||
m_chunkStart = -1;
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkWrite( unsigned int chunkname, void *pOutput, int size )
|
||||
{
|
||||
m_chunkPosition = m_riff.PositionGet();
|
||||
|
||||
m_chunkName = chunkname;
|
||||
m_chunkSize = size;
|
||||
|
||||
m_riff.WriteInt( chunkname );
|
||||
m_riff.WriteInt( size );
|
||||
m_riff.WriteData( pOutput, size );
|
||||
|
||||
m_chunkPosition = m_riff.PositionGet();
|
||||
|
||||
m_chunkPosition += m_chunkPosition & 1;
|
||||
|
||||
m_riff.PositionSet( m_chunkPosition );
|
||||
|
||||
m_chunkStart = -1;
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkWriteInt( int number )
|
||||
{
|
||||
m_riff.WriteInt( number );
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkWriteData( void *pOutput, int size )
|
||||
{
|
||||
m_riff.WriteData( pOutput, size );
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkFinish( void )
|
||||
{
|
||||
Assert( m_chunkStart != -1 );
|
||||
|
||||
m_chunkPosition = m_riff.PositionGet();
|
||||
|
||||
int size = m_chunkPosition - m_chunkStart - 8;
|
||||
|
||||
m_chunkPosition += m_chunkPosition & 1;
|
||||
|
||||
m_riff.PositionSet( m_chunkStart + sizeof( int ) );
|
||||
|
||||
m_riff.WriteInt( size );
|
||||
|
||||
m_riff.PositionSet( m_chunkPosition );
|
||||
|
||||
m_chunkStart = -1;
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkStart( unsigned int chunkname )
|
||||
{
|
||||
Assert( m_chunkStart == -1 );
|
||||
|
||||
m_chunkStart = m_riff.PositionGet();
|
||||
|
||||
m_riff.WriteInt( chunkname );
|
||||
m_riff.WriteInt( 0 );
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::ChunkSetPosition( int position )
|
||||
{
|
||||
m_riff.PositionSet( position );
|
||||
}
|
||||
|
||||
unsigned int IterateOutputRIFF::ChunkGetPosition( void )
|
||||
{
|
||||
return m_riff.PositionGet();
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::CopyChunkData( IterateRIFF& input )
|
||||
{
|
||||
if ( input.ChunkSize() > 0 )
|
||||
{
|
||||
char *buffer = new char[ input.ChunkSize() ];
|
||||
Assert( buffer );
|
||||
|
||||
input.ChunkRead( buffer );
|
||||
|
||||
// Don't copy/write the name or size, just the data itself
|
||||
ChunkWriteData( buffer, input.ChunkSize() );
|
||||
|
||||
delete[] buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void IterateOutputRIFF::SetLISETData( int position )
|
||||
{
|
||||
m_riff.HasLISETData( position );
|
||||
}
|
237
tier2/soundutils.cpp
Normal file
237
tier2/soundutils.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Helper methods + classes for sound
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include "tier2/soundutils.h"
|
||||
#include "tier2/riff.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#ifdef IS_WINDOWS_PC
|
||||
|
||||
#include <windows.h> // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!!
|
||||
#include <mmreg.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef _X360
|
||||
#include "xbox/xbox_win32stubs.h" // WAVEFORMATEX, WAVEFORMAT and ADPCM WAVEFORMAT!!!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RIFF reader/writers that use the file system
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFSIOReadBinary : public IFileReadBinary
|
||||
{
|
||||
public:
|
||||
// inherited from IFileReadBinary
|
||||
virtual int open( const char *pFileName );
|
||||
virtual int read( void *pOutput, int size, int file );
|
||||
virtual void seek( int file, int pos );
|
||||
virtual unsigned int tell( int file );
|
||||
virtual unsigned int size( int file );
|
||||
virtual void close( int file );
|
||||
};
|
||||
|
||||
class CFSIOWriteBinary : public IFileWriteBinary
|
||||
{
|
||||
public:
|
||||
virtual int create( const char *pFileName );
|
||||
virtual int write( void *pData, int size, int file );
|
||||
virtual void close( int file );
|
||||
virtual void seek( int file, int pos );
|
||||
virtual unsigned int tell( int file );
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Singletons
|
||||
//-----------------------------------------------------------------------------
|
||||
static CFSIOReadBinary s_FSIoIn;
|
||||
static CFSIOWriteBinary s_FSIoOut;
|
||||
|
||||
IFileReadBinary *g_pFSIOReadBinary = &s_FSIoIn;
|
||||
IFileWriteBinary *g_pFSIOWriteBinary = &s_FSIoOut;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RIFF reader that use the file system
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFSIOReadBinary::open( const char *pFileName )
|
||||
{
|
||||
return (int)g_pFullFileSystem->Open( pFileName, "rb" );
|
||||
}
|
||||
|
||||
int CFSIOReadBinary::read( void *pOutput, int size, int file )
|
||||
{
|
||||
if ( !file )
|
||||
return 0;
|
||||
|
||||
return g_pFullFileSystem->Read( pOutput, size, (FileHandle_t)file );
|
||||
}
|
||||
|
||||
void CFSIOReadBinary::seek( int file, int pos )
|
||||
{
|
||||
if ( !file )
|
||||
return;
|
||||
|
||||
g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
|
||||
}
|
||||
|
||||
unsigned int CFSIOReadBinary::tell( int file )
|
||||
{
|
||||
if ( !file )
|
||||
return 0;
|
||||
|
||||
return g_pFullFileSystem->Tell( (FileHandle_t)file );
|
||||
}
|
||||
|
||||
unsigned int CFSIOReadBinary::size( int file )
|
||||
{
|
||||
if ( !file )
|
||||
return 0;
|
||||
|
||||
return g_pFullFileSystem->Size( (FileHandle_t)file );
|
||||
}
|
||||
|
||||
void CFSIOReadBinary::close( int file )
|
||||
{
|
||||
if ( !file )
|
||||
return;
|
||||
|
||||
g_pFullFileSystem->Close( (FileHandle_t)file );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RIFF writer that use the file system
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFSIOWriteBinary::create( const char *pFileName )
|
||||
{
|
||||
g_pFullFileSystem->SetFileWritable( pFileName, true );
|
||||
return (int)g_pFullFileSystem->Open( pFileName, "wb" );
|
||||
}
|
||||
|
||||
int CFSIOWriteBinary::write( void *pData, int size, int file )
|
||||
{
|
||||
return g_pFullFileSystem->Write( pData, size, (FileHandle_t)file );
|
||||
}
|
||||
|
||||
void CFSIOWriteBinary::close( int file )
|
||||
{
|
||||
g_pFullFileSystem->Close( (FileHandle_t)file );
|
||||
}
|
||||
|
||||
void CFSIOWriteBinary::seek( int file, int pos )
|
||||
{
|
||||
g_pFullFileSystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
|
||||
}
|
||||
|
||||
unsigned int CFSIOWriteBinary::tell( int file )
|
||||
{
|
||||
return g_pFullFileSystem->Tell( (FileHandle_t)file );
|
||||
}
|
||||
|
||||
|
||||
#ifndef POSIX
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns the duration of a wav file
|
||||
//-----------------------------------------------------------------------------
|
||||
float GetWavSoundDuration( const char *pWavFile )
|
||||
{
|
||||
InFileRIFF riff( pWavFile, *g_pFSIOReadBinary );
|
||||
|
||||
// UNDONE: Don't use printf to handle errors
|
||||
if ( riff.RIFFName() != RIFF_WAVE )
|
||||
return 0.0f;
|
||||
|
||||
int nDataSize = 0;
|
||||
|
||||
// set up the iterator for the whole file (root RIFF is a chunk)
|
||||
IterateRIFF walk( riff, riff.RIFFSize() );
|
||||
|
||||
// This chunk must be first as it contains the wave's format
|
||||
// break out when we've parsed it
|
||||
char pFormatBuffer[ 1024 ];
|
||||
int nFormatSize;
|
||||
bool bFound = false;
|
||||
for ( ; walk.ChunkAvailable( ); walk.ChunkNext() )
|
||||
{
|
||||
switch ( walk.ChunkName() )
|
||||
{
|
||||
case WAVE_FMT:
|
||||
bFound = true;
|
||||
if ( walk.ChunkSize() > sizeof(pFormatBuffer) )
|
||||
{
|
||||
Warning( "oops, format tag too big!!!" );
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
nFormatSize = walk.ChunkSize();
|
||||
walk.ChunkRead( pFormatBuffer );
|
||||
break;
|
||||
|
||||
case WAVE_DATA:
|
||||
nDataSize += walk.ChunkSize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bFound )
|
||||
return 0.0f;
|
||||
|
||||
const WAVEFORMATEX *pHeader = (const WAVEFORMATEX *)pFormatBuffer;
|
||||
|
||||
int format = pHeader->wFormatTag;
|
||||
|
||||
int nBits = pHeader->wBitsPerSample;
|
||||
int nRate = pHeader->nSamplesPerSec;
|
||||
int nChannels = pHeader->nChannels;
|
||||
int nSampleSize = ( nBits * nChannels ) / 8;
|
||||
|
||||
// this can never be zero -- other functions divide by this.
|
||||
// This should never happen, but avoid crashing
|
||||
if ( nSampleSize <= 0 )
|
||||
{
|
||||
nSampleSize = 1;
|
||||
}
|
||||
|
||||
int nSampleCount = 0;
|
||||
float flTrueSampleSize = nSampleSize;
|
||||
|
||||
if ( format == WAVE_FORMAT_ADPCM )
|
||||
{
|
||||
nSampleSize = 1;
|
||||
|
||||
ADPCMWAVEFORMAT *pFormat = (ADPCMWAVEFORMAT *)pFormatBuffer;
|
||||
int blockSize = ((pFormat->wSamplesPerBlock - 2) * pFormat->wfx.nChannels ) / 2;
|
||||
blockSize += 7 * pFormat->wfx.nChannels;
|
||||
|
||||
int blockCount = nSampleCount / blockSize;
|
||||
int blockRem = nSampleCount % blockSize;
|
||||
|
||||
// total samples in complete blocks
|
||||
nSampleCount = blockCount * pFormat->wSamplesPerBlock;
|
||||
|
||||
// add remaining in a short block
|
||||
if ( blockRem )
|
||||
{
|
||||
nSampleCount += pFormat->wSamplesPerBlock - (((blockSize - blockRem) * 2) / nChannels);
|
||||
}
|
||||
|
||||
flTrueSampleSize = 0.5f;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
nSampleCount = nDataSize / nSampleSize;
|
||||
}
|
||||
|
||||
float flDuration = (float)nSampleCount / (float)nRate;
|
||||
return flDuration;
|
||||
}
|
||||
#endif
|
117
tier2/tier2.cpp
Normal file
117
tier2/tier2.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A higher level link library for general use in the game and tools.
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#include <tier2/tier2.h>
|
||||
#include "tier0/dbg.h"
|
||||
#include "filesystem.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "materialsystem/imaterialsystemhardwareconfig.h"
|
||||
#include "materialsystem/IColorCorrection.h"
|
||||
#include "materialsystem/idebugtextureinfo.h"
|
||||
#include "materialsystem/ivballoctracker.h"
|
||||
#include "inputsystem/iinputsystem.h"
|
||||
#include "networksystem/inetworksystem.h"
|
||||
#include "p4lib/ip4.h"
|
||||
#include "mdllib/mdllib.h"
|
||||
#include "filesystem/IQueuedLoader.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// These tier2 libraries must be set by any users of this library.
|
||||
// They can be set by calling ConnectTier2Libraries or InitDefaultFileSystem.
|
||||
// It is hoped that setting this, and using this library will be the common mechanism for
|
||||
// allowing link libraries to access tier2 library interfaces
|
||||
//-----------------------------------------------------------------------------
|
||||
IFileSystem *g_pFullFileSystem = 0;
|
||||
IMaterialSystem *materials = 0;
|
||||
IMaterialSystem *g_pMaterialSystem = 0;
|
||||
IInputSystem *g_pInputSystem = 0;
|
||||
INetworkSystem *g_pNetworkSystem = 0;
|
||||
IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig = 0;
|
||||
IDebugTextureInfo *g_pMaterialSystemDebugTextureInfo = 0;
|
||||
IVBAllocTracker *g_VBAllocTracker = 0;
|
||||
IColorCorrectionSystem *colorcorrection = 0;
|
||||
IP4 *p4 = 0;
|
||||
IMdlLib *mdllib = 0;
|
||||
IQueuedLoader *g_pQueuedLoader = 0;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Call this to connect to all tier 2 libraries.
|
||||
// It's up to the caller to check the globals it cares about to see if ones are missing
|
||||
//-----------------------------------------------------------------------------
|
||||
void ConnectTier2Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount )
|
||||
{
|
||||
// Don't connect twice..
|
||||
Assert( !g_pFullFileSystem && !materials && !g_pInputSystem && !g_pNetworkSystem &&
|
||||
!p4 && !mdllib && !g_pMaterialSystemDebugTextureInfo && !g_VBAllocTracker &&
|
||||
!g_pMaterialSystemHardwareConfig && !g_pQueuedLoader );
|
||||
|
||||
for ( int i = 0; i < nFactoryCount; ++i )
|
||||
{
|
||||
if ( !g_pFullFileSystem )
|
||||
{
|
||||
g_pFullFileSystem = ( IFileSystem * )pFactoryList[i]( FILESYSTEM_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !materials )
|
||||
{
|
||||
g_pMaterialSystem = materials = ( IMaterialSystem * )pFactoryList[i]( MATERIAL_SYSTEM_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pInputSystem )
|
||||
{
|
||||
g_pInputSystem = ( IInputSystem * )pFactoryList[i]( INPUTSYSTEM_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pNetworkSystem )
|
||||
{
|
||||
g_pNetworkSystem = ( INetworkSystem * )pFactoryList[i]( NETWORKSYSTEM_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pMaterialSystemHardwareConfig )
|
||||
{
|
||||
g_pMaterialSystemHardwareConfig = ( IMaterialSystemHardwareConfig * )pFactoryList[i]( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pMaterialSystemDebugTextureInfo )
|
||||
{
|
||||
g_pMaterialSystemDebugTextureInfo = (IDebugTextureInfo*)pFactoryList[i]( DEBUG_TEXTURE_INFO_VERSION, 0 );
|
||||
}
|
||||
if ( !g_VBAllocTracker )
|
||||
{
|
||||
g_VBAllocTracker = (IVBAllocTracker*)pFactoryList[i]( VB_ALLOC_TRACKER_INTERFACE_VERSION, 0 );
|
||||
}
|
||||
if ( !colorcorrection )
|
||||
{
|
||||
colorcorrection = ( IColorCorrectionSystem * )pFactoryList[i]( COLORCORRECTION_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !p4 )
|
||||
{
|
||||
p4 = ( IP4 * )pFactoryList[i]( P4_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !mdllib )
|
||||
{
|
||||
mdllib = ( IMdlLib * )pFactoryList[i]( MDLLIB_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
if ( !g_pQueuedLoader )
|
||||
{
|
||||
g_pQueuedLoader = (IQueuedLoader *)pFactoryList[i]( QUEUEDLOADER_INTERFACE_VERSION, NULL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisconnectTier2Libraries()
|
||||
{
|
||||
|
||||
g_pFullFileSystem = 0;
|
||||
materials = g_pMaterialSystem = 0;
|
||||
g_pMaterialSystemHardwareConfig = 0;
|
||||
g_pMaterialSystemDebugTextureInfo = 0;
|
||||
g_pInputSystem = 0;
|
||||
g_pNetworkSystem = 0;
|
||||
colorcorrection = 0;
|
||||
p4 = 0;
|
||||
mdllib = 0;
|
||||
g_pQueuedLoader = 0;
|
||||
}
|
||||
|
||||
|
58
tier2/tier2.vpc
Normal file
58
tier2/tier2.vpc
Normal file
@ -0,0 +1,58 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// TIER2.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$macro SRCDIR ".."
|
||||
|
||||
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE;$SRCDIR\public\tier2"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "tier2"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "beamsegdraw.cpp"
|
||||
$File "defaultfilesystem.cpp"
|
||||
$File "dmconnect.cpp"
|
||||
$file "fileutils.cpp"
|
||||
$File "keybindings.cpp"
|
||||
$File "$SRCDIR\public\map_utils.cpp"
|
||||
$File "$SRCDIR\public\materialsystem\MaterialSystemUtil.cpp"
|
||||
$File "camerautils.cpp"
|
||||
$File "meshutils.cpp"
|
||||
$File "p4helpers.cpp"
|
||||
$File "renderutils.cpp"
|
||||
$File "riff.cpp"
|
||||
$File "soundutils.cpp"
|
||||
$File "tier2.cpp"
|
||||
$File "util_init.cpp"
|
||||
$File "utlstreambuffer.cpp"
|
||||
$File "vconfig.cpp"
|
||||
$File "keyvaluesmacros.cpp"
|
||||
}
|
||||
|
||||
$Folder "Public Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\tier2\beamsegdraw.h"
|
||||
$File "$SRCDIR\public\tier2\fileutils.h"
|
||||
$File "$SRCDIR\public\tier2\camerautils.h"
|
||||
$File "$SRCDIR\public\tier2\meshutils.h"
|
||||
$File "$SRCDIR\public\tier2\keybindings.h"
|
||||
$File "$SRCDIR\public\tier2\renderutils.h"
|
||||
$File "$SRCDIR\public\tier2\riff.h"
|
||||
$File "$SRCDIR\public\tier2\soundutils.h"
|
||||
$File "$SRCDIR\public\tier2\tier2.h"
|
||||
$File "$SRCDIR\public\tier2\utlstreambuffer.h"
|
||||
$File "$SRCDIR\public\tier2\vconfig.h"
|
||||
$File "$SRCDIR\public\tier2\keyvaluesmacros.h"
|
||||
}
|
||||
}
|
50
tier2/util_init.cpp
Normal file
50
tier2/util_init.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: perform initialization needed in most command line programs
|
||||
//
|
||||
//===================================================================================-=//
|
||||
|
||||
#include <tier0/platform.h>
|
||||
#include <tier2/tier2.h>
|
||||
#include <mathlib/mathlib.h>
|
||||
#include <tier0/icommandline.h>
|
||||
#include "tier0/memalloc.h"
|
||||
#include "tier0/progressbar.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
|
||||
static void PrintFReportHandler(char const *job_name, int total_units_to_do, int n_units_completed)
|
||||
{
|
||||
static bool work_in_progress=false;
|
||||
static char LastJobName[1024];
|
||||
if ( Q_strncmp( LastJobName, job_name, sizeof( LastJobName ) ) )
|
||||
{
|
||||
if ( work_in_progress )
|
||||
printf("..done\n");
|
||||
Q_strncpy( LastJobName, job_name, sizeof( LastJobName ) );
|
||||
}
|
||||
if ( (total_units_to_do > 0 ) && (total_units_to_do >= n_units_completed) )
|
||||
{
|
||||
int percent_done=(100*n_units_completed)/total_units_to_do;
|
||||
printf("\r%s : %d%%",LastJobName, percent_done );
|
||||
work_in_progress = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s\n",LastJobName);
|
||||
work_in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InitCommandLineProgram( int argc, char **argv )
|
||||
{
|
||||
MathLib_Init( 1,1,1,0,false,true,true,true);
|
||||
CommandLine()->CreateCmdLine( argc, argv );
|
||||
InitDefaultFileSystem();
|
||||
InstallProgressReportHandler( PrintFReportHandler );
|
||||
|
||||
// By default, command line programs should not use the new assert dialog,
|
||||
// and any asserts should be fatal, unless we are being debugged
|
||||
if ( !Plat_IsInDebugSession() )
|
||||
SpewOutputFunc( DefaultSpewFuncAbortOnAsserts );
|
||||
}
|
386
tier2/utlstreambuffer.cpp
Normal file
386
tier2/utlstreambuffer.cpp
Normal file
@ -0,0 +1,386 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
// Serialization/unserialization buffer
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include "tier2/utlstreambuffer.h"
|
||||
#include "tier2/tier2.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// default stream chunk size
|
||||
//-----------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
DEFAULT_STREAM_CHUNK_SIZE = 16 * 1024
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CUtlStreamBuffer::CUtlStreamBuffer( ) : BaseClass( DEFAULT_STREAM_CHUNK_SIZE, DEFAULT_STREAM_CHUNK_SIZE, 0 )
|
||||
{
|
||||
SetUtlBufferOverflowFuncs( &CUtlStreamBuffer::StreamGetOverflow, &CUtlStreamBuffer::StreamPutOverflow );
|
||||
m_hFileHandle = FILESYSTEM_INVALID_HANDLE;
|
||||
m_pFileName = NULL;
|
||||
m_pPath = NULL;
|
||||
}
|
||||
|
||||
CUtlStreamBuffer::CUtlStreamBuffer( const char *pFileName, const char *pPath, int nFlags, bool bDelayOpen ) :
|
||||
BaseClass( DEFAULT_STREAM_CHUNK_SIZE, DEFAULT_STREAM_CHUNK_SIZE, nFlags )
|
||||
{
|
||||
SetUtlBufferOverflowFuncs( &CUtlStreamBuffer::StreamGetOverflow, &CUtlStreamBuffer::StreamPutOverflow );
|
||||
|
||||
if ( bDelayOpen )
|
||||
{
|
||||
m_pFileName = V_strdup( pFileName );
|
||||
|
||||
if ( pPath )
|
||||
{
|
||||
int nPathLen = Q_strlen( pPath );
|
||||
m_pPath = new char[ nPathLen + 1 ];
|
||||
Q_strcpy( m_pPath, pPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPath = new char[ 1 ];
|
||||
m_pPath[0] = 0;
|
||||
}
|
||||
|
||||
m_hFileHandle = FILESYSTEM_INVALID_HANDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFileName = NULL;
|
||||
m_pPath = NULL;
|
||||
m_hFileHandle = OpenFile( pFileName, pPath );
|
||||
if ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( IsReadOnly() )
|
||||
{
|
||||
// NOTE: MaxPut may not actually be this exact size for text files;
|
||||
// it could be slightly less owing to the /r/n -> /n conversion
|
||||
m_nMaxPut = g_pFullFileSystem->Size( m_hFileHandle );
|
||||
|
||||
// Read in the first bytes of the file
|
||||
if ( Size() > 0 )
|
||||
{
|
||||
int nSizeToRead = min( Size(), m_nMaxPut );
|
||||
ReadBytesFromFile( nSizeToRead, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CUtlStreamBuffer::Close()
|
||||
{
|
||||
if ( !IsReadOnly() )
|
||||
{
|
||||
// Write the final bytes
|
||||
int nBytesToWrite = TellPut() - m_nOffset;
|
||||
if ( nBytesToWrite > 0 )
|
||||
{
|
||||
if ( ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE ) && m_pFileName )
|
||||
{
|
||||
m_hFileHandle = OpenFile( m_pFileName, m_pPath );
|
||||
if( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
Error( "CUtlStreamBuffer::Close() Unable to open file %s!\n", m_pFileName );
|
||||
}
|
||||
}
|
||||
if ( m_hFileHandle != FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
if ( g_pFullFileSystem )
|
||||
{
|
||||
int nBytesWritten = g_pFullFileSystem->Write( Base(), nBytesToWrite, m_hFileHandle );
|
||||
if( nBytesWritten != nBytesToWrite )
|
||||
{
|
||||
Error( "CUtlStreamBuffer::Close() Write %s failed %d != %d.\n", m_pFileName, nBytesWritten, nBytesToWrite );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hFileHandle != FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
if ( g_pFullFileSystem )
|
||||
g_pFullFileSystem->Close( m_hFileHandle );
|
||||
m_hFileHandle = FILESYSTEM_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if ( m_pFileName )
|
||||
{
|
||||
delete[] m_pFileName;
|
||||
m_pFileName = NULL;
|
||||
}
|
||||
|
||||
if ( m_pPath )
|
||||
{
|
||||
delete[] m_pPath;
|
||||
m_pPath = NULL;
|
||||
}
|
||||
|
||||
m_Error = 0;
|
||||
}
|
||||
|
||||
CUtlStreamBuffer::~CUtlStreamBuffer()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Open the file. normally done in constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlStreamBuffer::Open( const char *pFileName, const char *pPath, int nFlags )
|
||||
{
|
||||
if ( IsOpen() )
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
m_Get = 0;
|
||||
m_Put = 0;
|
||||
m_nTab = 0;
|
||||
m_nOffset = 0;
|
||||
m_Flags = nFlags;
|
||||
m_hFileHandle = OpenFile( pFileName, pPath );
|
||||
if ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
return;
|
||||
|
||||
if ( IsReadOnly() )
|
||||
{
|
||||
// NOTE: MaxPut may not actually be this exact size for text files;
|
||||
// it could be slightly less owing to the /r/n -> /n conversion
|
||||
m_nMaxPut = g_pFullFileSystem->Size( m_hFileHandle );
|
||||
|
||||
// Read in the first bytes of the file
|
||||
if ( Size() > 0 )
|
||||
{
|
||||
int nSizeToRead = min( Size(), m_nMaxPut );
|
||||
ReadBytesFromFile( nSizeToRead, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_Memory.NumAllocated() != 0 )
|
||||
{
|
||||
m_nMaxPut = -1;
|
||||
AddNullTermination();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nMaxPut = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is the file open?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlStreamBuffer::IsOpen() const
|
||||
{
|
||||
if ( m_hFileHandle != FILESYSTEM_INVALID_HANDLE )
|
||||
return true;
|
||||
|
||||
// Delayed open case
|
||||
return ( m_pFileName != 0 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Grow allocation size to fit requested size
|
||||
//-----------------------------------------------------------------------------
|
||||
void CUtlStreamBuffer::GrowAllocatedSize( int nSize )
|
||||
{
|
||||
int nNewSize = Size();
|
||||
if ( nNewSize < nSize + 1 )
|
||||
{
|
||||
while ( nNewSize < nSize + 1 )
|
||||
{
|
||||
nNewSize += DEFAULT_STREAM_CHUNK_SIZE;
|
||||
}
|
||||
m_Memory.Grow( nNewSize - Size() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Load up more of the stream when we overflow
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlStreamBuffer::StreamPutOverflow( int nSize )
|
||||
{
|
||||
if ( !IsValid() || IsReadOnly() )
|
||||
return false;
|
||||
|
||||
// Make sure the allocated size is at least as big as the requested size
|
||||
if ( nSize > 0 )
|
||||
{
|
||||
GrowAllocatedSize( nSize + 2 );
|
||||
}
|
||||
|
||||
// Don't write the last byte (for NULL termination logic to work)
|
||||
int nBytesToWrite = TellPut() - m_nOffset - 1;
|
||||
if ( ( nBytesToWrite > 0 ) || ( nSize < 0 ) )
|
||||
{
|
||||
if ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
m_hFileHandle = OpenFile( m_pFileName, m_pPath );
|
||||
if( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nBytesToWrite > 0 )
|
||||
{
|
||||
int nBytesWritten = g_pFullFileSystem->Write( Base(), nBytesToWrite, m_hFileHandle );
|
||||
if ( nBytesWritten != nBytesToWrite )
|
||||
{
|
||||
m_Error |= FILE_WRITE_ERROR;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is necessary to deal with auto-NULL terminiation
|
||||
m_Memory[0] = *(unsigned char*)PeekPut( -1 );
|
||||
if ( TellPut() < Size() )
|
||||
{
|
||||
m_Memory[1] = *(unsigned char*)PeekPut( );
|
||||
}
|
||||
m_nOffset = TellPut() - 1;
|
||||
}
|
||||
|
||||
if ( nSize < 0 )
|
||||
{
|
||||
m_nOffset = -nSize-1;
|
||||
g_pFullFileSystem->Seek( m_hFileHandle, m_nOffset, FILESYSTEM_SEEK_HEAD );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Reads bytes from the file; fixes up maxput if necessary and null terminates
|
||||
//-----------------------------------------------------------------------------
|
||||
int CUtlStreamBuffer::ReadBytesFromFile( int nBytesToRead, int nReadOffset )
|
||||
{
|
||||
if ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
if ( !m_pFileName )
|
||||
{
|
||||
Warning( "File has not been opened!\n" );
|
||||
Assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_hFileHandle = OpenFile( m_pFileName, m_pPath );
|
||||
if ( m_hFileHandle == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
Error( "Unable to read file %s!\n", m_pFileName );
|
||||
return 0;
|
||||
}
|
||||
if ( m_nOffset != 0 )
|
||||
{
|
||||
g_pFullFileSystem->Seek( m_hFileHandle, m_nOffset, FILESYSTEM_SEEK_HEAD );
|
||||
}
|
||||
}
|
||||
|
||||
char *pReadPoint = (char*)Base() + nReadOffset;
|
||||
int nBytesRead = g_pFullFileSystem->Read( pReadPoint, nBytesToRead, m_hFileHandle );
|
||||
if ( nBytesRead != nBytesToRead )
|
||||
{
|
||||
// Since max put is a guess at the start,
|
||||
// we need to shrink it based on the actual # read
|
||||
if ( m_nMaxPut > TellGet() + nReadOffset + nBytesRead )
|
||||
{
|
||||
m_nMaxPut = TellGet() + nReadOffset + nBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
if ( nReadOffset + nBytesRead < Size() )
|
||||
{
|
||||
// This is necessary to deal with auto-NULL terminiation
|
||||
pReadPoint[nBytesRead] = 0;
|
||||
}
|
||||
|
||||
return nBytesRead;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Load up more of the stream when we overflow
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CUtlStreamBuffer::StreamGetOverflow( int nSize )
|
||||
{
|
||||
if ( !IsValid() || !IsReadOnly() )
|
||||
return false;
|
||||
|
||||
// Shift the unread bytes down
|
||||
// NOTE: Can't use the partial overlap path if we're seeking. We'll
|
||||
// get negative sizes passed in if we're seeking.
|
||||
int nUnreadBytes;
|
||||
bool bHasPartialOverlap = ( nSize >= 0 ) && ( TellGet() >= m_nOffset ) && ( TellGet() <= m_nOffset + Size() );
|
||||
if ( bHasPartialOverlap )
|
||||
{
|
||||
nUnreadBytes = Size() - ( TellGet() - m_nOffset );
|
||||
if ( ( TellGet() != m_nOffset ) && ( nUnreadBytes > 0 ) )
|
||||
{
|
||||
memmove( Base(), (const char*)Base() + TellGet() - m_nOffset, nUnreadBytes );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nOffset = TellGet();
|
||||
g_pFullFileSystem->Seek( m_hFileHandle, m_nOffset, FILESYSTEM_SEEK_HEAD );
|
||||
nUnreadBytes = 0;
|
||||
}
|
||||
|
||||
// Make sure the allocated size is at least as big as the requested size
|
||||
if ( nSize > 0 )
|
||||
{
|
||||
GrowAllocatedSize( nSize );
|
||||
}
|
||||
|
||||
int nBytesToRead = Size() - nUnreadBytes;
|
||||
int nBytesRead = ReadBytesFromFile( nBytesToRead, nUnreadBytes );
|
||||
if ( nBytesRead == 0 )
|
||||
return false;
|
||||
|
||||
m_nOffset = TellGet();
|
||||
return ( nBytesRead + nUnreadBytes >= nSize );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// open file unless already failed to open
|
||||
//-----------------------------------------------------------------------------
|
||||
FileHandle_t CUtlStreamBuffer::OpenFile( const char *pFileName, const char *pPath )
|
||||
{
|
||||
if ( m_Error & FILE_OPEN_ERROR )
|
||||
return FILESYSTEM_INVALID_HANDLE;
|
||||
|
||||
char openflags[ 3 ] = "xx";
|
||||
openflags[ 0 ] = IsReadOnly() ? 'r' : 'w';
|
||||
openflags[ 1 ] = IsText() && !ContainsCRLF() ? 't' : 'b';
|
||||
|
||||
FileHandle_t fh = g_pFullFileSystem->Open( pFileName, openflags, pPath );
|
||||
if( fh == FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
m_Error |= FILE_OPEN_ERROR;
|
||||
}
|
||||
|
||||
return fh;
|
||||
}
|
149
tier2/vconfig.cpp
Normal file
149
tier2/vconfig.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Utilities for setting vproject settings
|
||||
//
|
||||
//===========================================================================//
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined( _X360 )
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <direct.h>
|
||||
#include <io.h> // _chmod
|
||||
#include <process.h>
|
||||
#endif
|
||||
#if defined( _X360 )
|
||||
#include "xbox/xbox_win32stubs.h"
|
||||
#endif
|
||||
#include "vconfig.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the string value of a registry key
|
||||
// Input : *pName - name of the subKey to read
|
||||
// *pReturn - string buffer to receive read string
|
||||
// size - size of specified buffer
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GetVConfigRegistrySetting( const char *pName, char *pReturn, int size )
|
||||
{
|
||||
// Open the key
|
||||
HKEY hregkey;
|
||||
// Changed to HKEY_CURRENT_USER from HKEY_LOCAL_MACHINE
|
||||
if ( RegOpenKeyEx( HKEY_CURRENT_USER, VPROJECT_REG_KEY, 0, KEY_QUERY_VALUE, &hregkey ) != ERROR_SUCCESS )
|
||||
return false;
|
||||
|
||||
// Get the value
|
||||
DWORD dwSize = size;
|
||||
if ( RegQueryValueEx( hregkey, pName, NULL, NULL,(LPBYTE) pReturn, &dwSize ) != ERROR_SUCCESS )
|
||||
return false;
|
||||
|
||||
// Close the key
|
||||
RegCloseKey( hregkey );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sends a global system message to alert programs to a changed environment variable
|
||||
//-----------------------------------------------------------------------------
|
||||
void NotifyVConfigRegistrySettingChanged( void )
|
||||
{
|
||||
DWORD_PTR dwReturnValue = 0;
|
||||
|
||||
// Propagate changes so that environment variables takes immediate effect!
|
||||
SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, (LPARAM) "Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the registry entry to a string value, under the given subKey
|
||||
// Input : *pName - name of the subKey to set
|
||||
// *pValue - string value
|
||||
//-----------------------------------------------------------------------------
|
||||
void SetVConfigRegistrySetting( const char *pName, const char *pValue, bool bNotify )
|
||||
{
|
||||
HKEY hregkey;
|
||||
|
||||
// Changed to HKEY_CURRENT_USER from HKEY_LOCAL_MACHINE
|
||||
// Open the key
|
||||
if ( RegCreateKeyEx(
|
||||
HKEY_CURRENT_USER, // base key
|
||||
VPROJECT_REG_KEY, // subkey
|
||||
0, // reserved
|
||||
0, // lpClass
|
||||
0, // options
|
||||
(REGSAM)KEY_ALL_ACCESS, // access desired
|
||||
NULL, // security attributes
|
||||
&hregkey, // result
|
||||
NULL // tells if it created the key or not (which we don't care)
|
||||
) != ERROR_SUCCESS )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the value to the string passed in
|
||||
int nType = strchr( pValue, '%' ) ? REG_EXPAND_SZ : REG_SZ;
|
||||
RegSetValueEx( hregkey, pName, 0, nType, (const unsigned char *)pValue, (int) strlen(pValue) );
|
||||
|
||||
// Notify other programs
|
||||
if ( bNotify )
|
||||
{
|
||||
NotifyVConfigRegistrySettingChanged();
|
||||
}
|
||||
|
||||
// Close the key
|
||||
RegCloseKey( hregkey );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes the obsolete user keyvalue
|
||||
// Input : *pName - name of the subKey to set
|
||||
// *pValue - string value
|
||||
//-----------------------------------------------------------------------------
|
||||
bool RemoveObsoleteVConfigRegistrySetting( const char *pValueName, char *pOldValue, int size )
|
||||
{
|
||||
// Open the key
|
||||
HKEY hregkey;
|
||||
if ( RegOpenKeyEx( HKEY_CURRENT_USER, "Environment", 0, (REGSAM)KEY_ALL_ACCESS, &hregkey ) != ERROR_SUCCESS )
|
||||
return false;
|
||||
|
||||
// Return the old state if they've requested it
|
||||
if ( pOldValue != NULL )
|
||||
{
|
||||
DWORD dwSize = size;
|
||||
|
||||
// Get the value
|
||||
if ( RegQueryValueEx( hregkey, pValueName, NULL, NULL,(LPBYTE) pOldValue, &dwSize ) != ERROR_SUCCESS )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the value
|
||||
if ( RegDeleteValue( hregkey, pValueName ) != ERROR_SUCCESS )
|
||||
return false;
|
||||
|
||||
// Close the key
|
||||
RegCloseKey( hregkey );
|
||||
|
||||
// Notify other programs
|
||||
NotifyVConfigRegistrySettingChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Take a user-defined environment variable and swap it out for the internally used one
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool ConvertObsoleteVConfigRegistrySetting( const char *pValueName )
|
||||
{
|
||||
char szValue[MAX_PATH];
|
||||
if ( RemoveObsoleteVConfigRegistrySetting( pValueName, szValue, sizeof( szValue ) ) )
|
||||
{
|
||||
// Set it up the correct way
|
||||
SetVConfigRegistrySetting( pValueName, szValue );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user