diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tier2 | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'tier2')
| -rw-r--r-- | tier2/beamsegdraw.cpp | 235 | ||||
| -rw-r--r-- | tier2/camerautils.cpp | 99 | ||||
| -rw-r--r-- | tier2/defaultfilesystem.cpp | 57 | ||||
| -rw-r--r-- | tier2/dmconnect.cpp | 62 | ||||
| -rw-r--r-- | tier2/fileutils.cpp | 304 | ||||
| -rw-r--r-- | tier2/keybindings.cpp | 143 | ||||
| -rw-r--r-- | tier2/keyvaluesmacros.cpp | 462 | ||||
| -rw-r--r-- | tier2/meshutils.cpp | 104 | ||||
| -rw-r--r-- | tier2/p4helpers.cpp | 138 | ||||
| -rw-r--r-- | tier2/renderutils.cpp | 916 | ||||
| -rw-r--r-- | tier2/riff.cpp | 506 | ||||
| -rw-r--r-- | tier2/soundutils.cpp | 237 | ||||
| -rw-r--r-- | tier2/tier2.cpp | 117 | ||||
| -rw-r--r-- | tier2/tier2.vpc | 58 | ||||
| -rw-r--r-- | tier2/util_init.cpp | 50 | ||||
| -rw-r--r-- | tier2/utlstreambuffer.cpp | 386 | ||||
| -rw-r--r-- | tier2/vconfig.cpp | 149 |
17 files changed, 4023 insertions, 0 deletions
diff --git a/tier2/beamsegdraw.cpp b/tier2/beamsegdraw.cpp new file mode 100644 index 0000000..fca4471 --- /dev/null +++ b/tier2/beamsegdraw.cpp @@ -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(); +} diff --git a/tier2/camerautils.cpp b/tier2/camerautils.cpp new file mode 100644 index 0000000..41d1dc7 --- /dev/null +++ b/tier2/camerautils.cpp @@ -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; +} + + diff --git a/tier2/defaultfilesystem.cpp b/tier2/defaultfilesystem.cpp new file mode 100644 index 0000000..b3a1662 --- /dev/null +++ b/tier2/defaultfilesystem.cpp @@ -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 ); +} diff --git a/tier2/dmconnect.cpp b/tier2/dmconnect.cpp new file mode 100644 index 0000000..b8b41f1 --- /dev/null +++ b/tier2/dmconnect.cpp @@ -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(); +} + + diff --git a/tier2/fileutils.cpp b/tier2/fileutils.cpp new file mode 100644 index 0000000..2a0ca59 --- /dev/null +++ b/tier2/fileutils.cpp @@ -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 ); +} + + diff --git a/tier2/keybindings.cpp b/tier2/keybindings.cpp new file mode 100644 index 0000000..d2c9257 --- /dev/null +++ b/tier2/keybindings.cpp @@ -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 ]; +} + + + diff --git a/tier2/keyvaluesmacros.cpp b/tier2/keyvaluesmacros.cpp new file mode 100644 index 0000000..11a5c97 --- /dev/null +++ b/tier2/keyvaluesmacros.cpp @@ -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(); +} diff --git a/tier2/meshutils.cpp b/tier2/meshutils.cpp new file mode 100644 index 0000000..4aa0144 --- /dev/null +++ b/tier2/meshutils.cpp @@ -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; + } +} diff --git a/tier2/p4helpers.cpp b/tier2/p4helpers.cpp new file mode 100644 index 0000000..9b32dfb --- /dev/null +++ b/tier2/p4helpers.cpp @@ -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 + diff --git a/tier2/renderutils.cpp b/tier2/renderutils.cpp new file mode 100644 index 0000000..41b8bc6 --- /dev/null +++ b/tier2/renderutils.cpp @@ -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(); +} diff --git a/tier2/riff.cpp b/tier2/riff.cpp new file mode 100644 index 0000000..9e36021 --- /dev/null +++ b/tier2/riff.cpp @@ -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 ); +}
\ No newline at end of file diff --git a/tier2/soundutils.cpp b/tier2/soundutils.cpp new file mode 100644 index 0000000..bebda85 --- /dev/null +++ b/tier2/soundutils.cpp @@ -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 diff --git a/tier2/tier2.cpp b/tier2/tier2.cpp new file mode 100644 index 0000000..7fd6143 --- /dev/null +++ b/tier2/tier2.cpp @@ -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; +} + + diff --git a/tier2/tier2.vpc b/tier2/tier2.vpc new file mode 100644 index 0000000..53ff36d --- /dev/null +++ b/tier2/tier2.vpc @@ -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" + } +} diff --git a/tier2/util_init.cpp b/tier2/util_init.cpp new file mode 100644 index 0000000..1fb1ddd --- /dev/null +++ b/tier2/util_init.cpp @@ -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 ); +} diff --git a/tier2/utlstreambuffer.cpp b/tier2/utlstreambuffer.cpp new file mode 100644 index 0000000..023a682 --- /dev/null +++ b/tier2/utlstreambuffer.cpp @@ -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; +} diff --git a/tier2/vconfig.cpp b/tier2/vconfig.cpp new file mode 100644 index 0000000..ff90afc --- /dev/null +++ b/tier2/vconfig.cpp @@ -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 |