//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "stdafx.h" #include "filesystem_tools.h" #include "KeyValues.h" #include "physdll.h" #include "materialsystem/imesh.h" #include "utlvector.h" char g_szAppName[] = "VPhysics perf test"; bool g_bCaptureOnFocus = false; IPhysics *physics = NULL; IPhysicsCollision *physcollision = NULL; IPhysicsSurfaceProps *physprops = NULL; IMaterial *g_materialFlatshaded = NULL; IMaterial *g_pWireframeMaterial = NULL; int gKeys[256]; const objectparams_t g_PhysDefaultObjectParams = { NULL, 1.0f, //mass 1.0f, // inertia 0.0f, // damping 0.0f, // rotdamping 0.05f, // rotIntertiaLimit "DEFAULT", NULL,// game data 0.f, // volume (leave 0 if you don't have one or call physcollision->CollideVolume() to compute it) 1.0f, // drag coefficient true,// enable collisions? }; void AddSurfacepropFile( const char *pFileName, IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ) { // Load file into memory FileHandle_t file = pFileSystem->Open( pFileName, "rb" ); if ( file ) { int len = pFileSystem->Size( file ); // read the file char *buffer = (char *)stackalloc( len+1 ); pFileSystem->Read( buffer, len, file ); pFileSystem->Close( file ); buffer[len] = 0; pProps->ParseSurfaceData( pFileName, buffer ); // buffer is on the stack, no need to free } } void PhysParseSurfaceData( IPhysicsSurfaceProps *pProps, IFileSystem *pFileSystem ) { const char *SURFACEPROP_MANIFEST_FILE = "scripts/surfaceproperties_manifest.txt"; KeyValues *manifest = new KeyValues( SURFACEPROP_MANIFEST_FILE ); if ( manifest->LoadFromFile( pFileSystem, SURFACEPROP_MANIFEST_FILE, "GAME" ) ) { for ( KeyValues *sub = manifest->GetFirstSubKey(); sub != NULL; sub = sub->GetNextKey() ) { if ( !Q_stricmp( sub->GetName(), "file" ) ) { // Add AddSurfacepropFile( sub->GetString(), pProps, pFileSystem ); continue; } Warning( "surfaceprops::Init: Manifest '%s' with bogus file type '%s', expecting 'file'\n", SURFACEPROP_MANIFEST_FILE, sub->GetName() ); } } else { Error( "Unable to load manifest file '%s'\n", SURFACEPROP_MANIFEST_FILE ); } manifest->deleteThis(); } struct physics_test_object_t { IPhysicsObject *pPhysics; ICollisionQuery *pModel; }; struct physicstest_t { IPhysicsEnvironment *physenv; CUtlVector list; void Clear() { physenv->SetQuickDelete( true ); for ( int i = 0; i < list.Count(); i++ ) { physcollision->DestroyQueryModel( list[i].pModel ); physenv->DestroyObject( list[i].pPhysics ); } list.Purge(); physics->DestroyEnvironment( physenv ); } void InitEnvironment() { physenv = physics->CreateEnvironment(); //g_EntityCollisionHash = physics->CreateObjectPairHash(); physenv->EnableDeleteQueue( true ); //physenv->SetCollisionSolver( &g_Collisions ); //physenv->SetCollisionEventHandler( &g_Collisions ); //physenv->SetConstraintEventHandler( g_pConstraintEvents ); //physenv->SetObjectEventHandler( &g_Objects ); physenv->SetSimulationTimestep( DEFAULT_TICK_INTERVAL ); // 15 ms per tick // HL Game gravity, not real-world gravity physenv->SetGravity( Vector( 0, 0, -600.0f ) ); physenv->SetAirDensity( 0.5f ); } int AddObject( IPhysicsObject *pObject ) { int index = list.AddToTail(); list[index].pPhysics = pObject; list[index].pModel = physcollision->CreateQueryModel( (CPhysCollide *)pObject->GetCollide() ); return index; } void CreateGround( float size ) { { CPhysCollide *pCollide = physcollision->BBoxToCollide( Vector(-size,-size,-24), Vector(size,size,0) ); objectparams_t params = g_PhysDefaultObjectParams; IPhysicsObject *pGround = physenv->CreatePolyObjectStatic( pCollide, physprops->GetSurfaceIndex( "default" ), vec3_origin, vec3_angle, ¶ms ); AddObject( pGround ); } for ( int i = 0; i < 20; i++ ) { CPhysCollide *pCollide = physcollision->BBoxToCollide( Vector(-24,-24,-24), Vector(24,24,24) ); objectparams_t params = g_PhysDefaultObjectParams; params.mass = 150.0f; IPhysicsObject *pGround = physenv->CreatePolyObject( pCollide, physprops->GetSurfaceIndex( "default" ), Vector(64*(i%4),64 * (i%5),1024), vec3_angle, ¶ms ); AddObject( pGround ); pGround->Wake(); } } void Explode( const Vector &origin, float force ) { for ( int i = 0; i < list.Count(); i++ ) { if ( !list[i].pPhysics->IsMoveable() ) continue; Vector pos, dir; list[i].pPhysics->GetPosition( &pos, NULL ); dir = pos - origin; dir.z += 10; VectorNormalize( dir ); list[i].pPhysics->ApplyForceCenter( dir * force ); } } void RandomColor( float *color, int key ) { static bool first = true; static colorVec colors[256]; if ( first ) { int r, g, b; first = false; for ( int i = 0; i < 256; i++ ) { do { r = rand()&255; g = rand()&255; b = rand()&255; } while ( (r+g+b)<256 ); colors[i].r = r; colors[i].g = g; colors[i].b = b; colors[i].a = 255; } } int index = key & 255; color[0] = colors[index].r * (1.f / 255.f); color[1] = colors[index].g * (1.f / 255.f); color[2] = colors[index].b * (1.f / 255.f); color[3] = colors[index].a * (1.f / 255.f); } void DrawObject( ICollisionQuery *pModel, IMaterial *pMaterial, IPhysicsObject *pObject ) { matrix3x4_t matrix; pObject->GetPositionMatrix( &matrix ); CMatRenderContextPtr pRenderContext(g_MaterialSystemApp.m_pMaterialSystem); pRenderContext->Bind( pMaterial ); int vertIndex = 0; for ( int i = 0; i < pModel->ConvexCount(); i++ ) { float color[4]; RandomColor( color, i + (int)pObject ); IMesh* pMatMesh = pRenderContext->GetDynamicMesh( ); CMeshBuilder meshBuilder; int triCount = pModel->TriangleCount( i ); meshBuilder.Begin( pMatMesh, MATERIAL_TRIANGLES, triCount ); for ( int j = 0; j < triCount; j++ ) { Vector objectSpaceVerts[3]; pModel->GetTriangleVerts( i, j, objectSpaceVerts ); for ( int k = 0; k < 3; k++ ) { Vector v; VectorTransform (objectSpaceVerts[k], matrix, v); meshBuilder.Position3fv( v.Base() ); meshBuilder.Color4fv( color ); meshBuilder.AdvanceVertex(); } } meshBuilder.End( false, true ); } } void Draw() { for ( int i = 0; i < list.Count(); i++ ) { DrawObject( list[i].pModel, g_materialFlatshaded, list[i].pPhysics ); } } void Simulate( float frametime ) { physenv->Simulate( frametime ); } }; physicstest_t staticTest; void AppInit( void ) { memset( gKeys, 0, sizeof(gKeys) ); CreateInterfaceFn physicsFactory = GetPhysicsFactory(); if (!(physics = (IPhysics *)physicsFactory( VPHYSICS_INTERFACE_VERSION, NULL )) || !(physcollision = (IPhysicsCollision *)physicsFactory( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL )) || !(physprops = (IPhysicsSurfaceProps *)physicsFactory( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION, NULL )) ) { return; } PhysParseSurfaceData( physprops, g_pFullFileSystem ); g_materialFlatshaded = g_MaterialSystemApp.m_pMaterialSystem->FindMaterial("debug/debugdrawflatpolygons", TEXTURE_GROUP_OTHER, true); g_pWireframeMaterial = g_MaterialSystemApp.m_pMaterialSystem->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER); staticTest.InitEnvironment(); staticTest.CreateGround( 1024 ); } void FPSControls( float frametime, float mouseDeltaX, float mouseDeltaY, Vector& cameraPosition, QAngle& cameraAngles, float speed ) { cameraAngles[1] -= mouseDeltaX; cameraAngles[0] -= mouseDeltaY; if ( cameraAngles[0] < -85 ) cameraAngles[0] = -85; if ( cameraAngles[0] > 85 ) cameraAngles[0] = 85; Vector forward, right, up; AngleVectors( cameraAngles, &forward, &right, &up ); if ( gKeys[ 'W' ] ) VectorMA( cameraPosition, frametime * speed, forward, cameraPosition ); if ( gKeys[ 'S' ] ) VectorMA( cameraPosition, -frametime * speed, forward, cameraPosition ); if ( gKeys[ 'A' ] ) VectorMA( cameraPosition, -frametime * speed, right, cameraPosition ); if ( gKeys[ 'D' ] ) VectorMA( cameraPosition, frametime * speed, right, cameraPosition ); } void SetupCamera( Vector& cameraPosition, QAngle& cameraAngles ) { CMatRenderContextPtr pRenderContext(g_MaterialSystemApp.m_pMaterialSystem); pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->LoadIdentity( ); pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up pRenderContext->Rotate( 90, 0, 0, 1 ); pRenderContext->Rotate( -cameraAngles[2], 1, 0, 0); // roll pRenderContext->Rotate( -cameraAngles[0], 0, 1, 0); // pitch pRenderContext->Rotate( -cameraAngles[1], 0, 0, 1); // yaw pRenderContext->Translate( -cameraPosition[0], -cameraPosition[1], -cameraPosition[2] ); } static Vector cameraPosition = Vector(0,0,128); static QAngle cameraAngles = vec3_angle; void AppRender( float frametime, float mouseDeltaX, float mouseDeltaY ) { FPSControls( frametime, mouseDeltaX, mouseDeltaY, cameraPosition, cameraAngles, 300 ); SetupCamera( cameraPosition, cameraAngles ); staticTest.Simulate( frametime ); staticTest.Draw(); } void AppExit( void ) { staticTest.Clear(); //physics->DestroyObjectPairHash( g_EntityCollisionHash ); //g_EntityCollisionHash = NULL; physics->DestroyAllCollisionSets(); } void AppKey( int key, int down ) { gKeys[ key & 255 ] = down; } void AppChar( int key ) { if ( key == ' ' ) { staticTest.Explode( cameraPosition, 150 * 100 ); } }