source-engine/movieobjects/dmeselection.cpp

577 lines
15 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "datamodel/dmelementfactoryhelper.h"
#include "movieobjects/dmeselection.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeComponent, CDmeComponent );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeComponent::OnConstruction()
{
m_Type.InitAndSet( this, "componentType", COMP_INVALID );
m_bComplete.InitAndSet( this, "complete", false );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeComponent::OnDestruction()
{
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeComponent::Resolve()
{
}
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeSingleIndexedComponent, CDmeSingleIndexedComponent );
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::OnConstruction()
{
m_CompleteCount.InitAndSet( this, "completeCount", 0 );
m_Components.Init( this, "components" );
m_Weights.Init( this, "weights" );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::OnDestruction()
{
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::Resolve()
{
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CDmeSingleIndexedComponent::Count() const
{
return IsComplete() ? m_CompleteCount.Get() : m_Components.Count();
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeSingleIndexedComponent::SetType( Component_t type )
{
switch ( type )
{
case COMP_VTX:
case COMP_FACE:
m_Type.Set( type );
return true;
default:
break;
}
return false;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::AddComponent( int component, float weight /*= 1.0f */ )
{
if ( IsComplete() )
return;
const int index( BinarySearch( component ) );
Assert( index >= 0 );
Assert( index <= m_Components.Count() );
if ( index == m_Components.Count() )
{
m_Components.AddToTail( component );
m_Weights.AddToTail( weight );
}
else if ( component == m_Components.Get( index ) )
{
Assert( index < m_Weights.Count() );
m_Weights.Set( index, weight );
}
else
{
m_Components.InsertBefore( index, component );
m_Weights.InsertBefore( index, weight );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::AddComponents( const CUtlVector< int > &components )
{
const int nComponents( components.Count() );
for ( int i( 0 ); i < nComponents; ++i )
{
AddComponent( components[ i ] );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::AddComponents(
const CUtlVector< int > &components, const CUtlVector< float > &weights )
{
const int nComponents( min( components.Count(), weights.Count() ) );
for ( int i( 0 ); i < nComponents; ++i )
{
AddComponent( components[ i ], weights[ i ] );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::RemoveComponent( int component )
{
Assert( !IsComplete() ); // TODO: Convert from complete to complete - component
const int cIndex = BinarySearch( component );
if ( cIndex >= m_Components.Count() || m_Components[ cIndex ] != component ) // Component not in selection
return;
m_Components.Remove( cIndex );
m_Weights.Remove( cIndex );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeSingleIndexedComponent::GetComponent( int index, int &component, float &weight ) const
{
if ( index < Count() )
{
if ( IsComplete() )
{
component = index;
weight = 1.0f;
}
else
{
component = m_Components[ index ];
weight = m_Weights[ index ];
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::GetComponents( CUtlVector< int > &components, CUtlVector< float > &weights ) const
{
if ( IsComplete() )
{
const int nComponents = Count();
int *pComponents = reinterpret_cast< int * >( alloca( nComponents * sizeof( int ) ) );
float *pWeights = reinterpret_cast< float * >( alloca( nComponents * sizeof( float ) ) );
for ( int i = 0; i < nComponents; ++i )
{
pComponents[ i ] = i;
pWeights[ i ] = 1.0f;
}
components.CopyArray( pComponents, nComponents );
weights.CopyArray( pWeights, nComponents );
}
else
{
components.RemoveAll();
components.CopyArray( m_Components.Base(), m_Components.Count() );
weights.RemoveAll();
weights.CopyArray( m_Weights.Base(), m_Weights.Count() );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::GetComponents( CUtlVector< int > &components ) const
{
if ( IsComplete() )
{
const int nComponents = Count();
int *pComponents = reinterpret_cast< int * >( alloca( nComponents * sizeof( int ) ) );
for ( int i = 0; i < nComponents; ++i )
{
pComponents[ i ] = i;
}
components.CopyArray( pComponents, nComponents );
}
else
{
components.RemoveAll();
components.CopyArray( m_Components.Base(), m_Components.Count() );
}
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::SetComplete( int nComplete )
{
m_bComplete.Set( true );
m_CompleteCount.Set( max( 0, nComplete ) );
m_Components.Purge();
m_Weights.Purge();
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
int CDmeSingleIndexedComponent::GetComplete() const
{
return IsComplete() ? m_CompleteCount.Get() : 0;
}
//-----------------------------------------------------------------------------
// Reset to an empty selection
//-----------------------------------------------------------------------------
inline void CDmeSingleIndexedComponent::Clear()
{
CDmeComponent::Clear();
m_CompleteCount.Set( 0 );
m_Components.RemoveAll();
m_Weights.RemoveAll();
}
//-----------------------------------------------------------------------------
// Searches for the component in the sorted component list and returns the
// index if it's found or if it's not found, returns the index at which it
// should be inserted to maintain the sorted order of the component list
//-----------------------------------------------------------------------------
int CDmeSingleIndexedComponent::BinarySearch( int component ) const
{
const CUtlVector< int > &components( m_Components.Get() );
const int nComponents( components.Count() );
int left( 0 );
int right( nComponents - 1 );
int mid;
while ( left <= right )
{
mid = ( left + right ) >> 1; // floor( ( left + right ) / 2.0 )
if ( component > m_Components[ mid ] )
{
left = mid + 1;
}
else if ( component < m_Components[ mid ] )
{
right = mid - 1;
}
else
{
return mid;
}
}
return left;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeSingleIndexedComponent::HasComponent( int component ) const
{
if ( IsComplete() )
return true;
const int cIndex = BinarySearch( component );
if ( cIndex >= m_Components.Count() )
return false;
if ( m_Components[ cIndex ] == component )
return true;
return false;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
bool CDmeSingleIndexedComponent::GetWeight( int component, float &weight ) const
{
Assert( !IsComplete() );
const int cIndex = BinarySearch( component );
if ( cIndex >= m_Components.Count() )
return false;
if ( m_Components[ cIndex ] == component )
{
weight = m_Weights[ cIndex ];
return true;
}
return false;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::Subtract( const CDmeSingleIndexedComponent &rhs )
{
const int nLhs = Count();
const int nRhs = rhs.Count();
int l = 0;
int r = 0;
if ( IsComplete() )
{
// TODO
Assert( 0 );
}
else
{
CUtlVector< int > newComponents;
newComponents.EnsureCapacity( nLhs );
CUtlVector< float > newWeights;
newWeights.EnsureCapacity( nLhs );
while ( l < nLhs || r < nRhs )
{
// In LHS but not RHS
while ( l < nLhs && ( r >= nRhs || m_Components[ l ] < rhs.m_Components[ r ] ) )
{
newComponents.AddToTail( m_Components[ l ] );
newWeights.AddToTail( m_Weights[ l ] );
++l;
}
// In RHS but not LHS
while ( r < nRhs && ( l >= nLhs || m_Components[ l ] > rhs.m_Components[ r ] ) )
{
++r;
}
// In Both LHS & RHS
while ( l < nLhs && r < nRhs && m_Components[ l ] == rhs.m_Components[ r ] )
{
++l;
++r;
}
}
m_Components.CopyArray( newComponents.Base(), newComponents.Count() );
m_Weights.CopyArray( newWeights.Base(), newWeights.Count() );
}
m_CompleteCount.Set( 0 );
m_bComplete.Set( false );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::Add( const CDmeSingleIndexedComponent &rhs )
{
int nLhs = Count();
const int nRhs = rhs.Count();
int l = 0;
int r = 0;
if ( IsComplete() )
{
if ( rhs.IsComplete() && nRhs > nLhs )
{
m_CompleteCount.Set( nRhs );
}
else
{
while ( r < nRhs )
{
if ( rhs.m_Components[ r ] >= nLhs )
{
// Got one that's greater than the complete count of this one
CUtlVector< int > newComponents;
newComponents.EnsureCapacity( nLhs + nRhs - r );
CUtlVector< float > newWeights;
newWeights.EnsureCapacity( nLhs + nRhs - r );
GetComponents( newComponents, newWeights );
while ( r < nRhs )
{
newComponents.AddToTail( rhs.m_Components[ r ] );
newWeights.AddToTail( rhs.m_Weights[ r ] );
++r;
}
m_Components.CopyArray( newComponents.Base(), newComponents.Count() );
m_Weights.CopyArray( newWeights.Base(), newWeights.Count() );
m_CompleteCount.Set( 0 );
m_bComplete.Set( false );
break;
}
++r;
}
}
}
else
{
CUtlVector< int > newComponents;
newComponents.EnsureCapacity( nLhs + nRhs * 0.5 ); // Just an estimate assuming 50% of the components in rhs aren't in lhs
CUtlVector< float > newWeights;
newWeights.EnsureCapacity( nLhs + nRhs * 0.5 ); // Just an estimate
while ( l < nLhs || r < nRhs )
{
while ( l < nLhs && ( r >= nRhs || m_Components[ l ] < rhs.m_Components[ r ] ) )
{
newComponents.AddToTail( m_Components[ l ] );
newWeights.AddToTail( m_Weights[ l ] );
++l;
}
// In RHS but not LHS
while ( r < nRhs && ( l >= nLhs || m_Components[ l ] > rhs.m_Components[ r ] ) )
{
newComponents.AddToTail( rhs.m_Components[ r ] );
newWeights.AddToTail( rhs.m_Weights[ r ] );
++r;
}
// In Both LHS & RHS
while ( l < nLhs && r < nRhs && m_Components[ l ] == rhs.m_Components[ r ] )
{
newComponents.AddToTail( m_Components[ l ] );
newWeights.AddToTail( m_Weights[ l ] );
++l;
++r;
}
}
m_Components.CopyArray( newComponents.Base(), newComponents.Count() );
m_Weights.CopyArray( newWeights.Base(), newWeights.Count() );
}
m_CompleteCount.Set( 0 );
m_bComplete.Set( false );
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void CDmeSingleIndexedComponent::Intersection( const CDmeSingleIndexedComponent &rhs )
{
const int nLhs = Count();
const int nRhs = rhs.Count();
int l = 0;
int r = 0;
if ( IsComplete() )
{
// TODO
Assert( 0 );
}
else
{
CUtlVector< int > newComponents;
newComponents.EnsureCapacity( nLhs );
CUtlVector< float > newWeights;
newWeights.EnsureCapacity( nLhs );
while ( l < nLhs || r < nRhs )
{
// In LHS but not RHS
while ( l < nLhs && ( r >= nRhs || m_Components[ l ] < rhs.m_Components[ r ] ) )
{
++l;
}
// In RHS but not LHS
while ( r < nRhs && ( l >= nLhs || m_Components[ l ] > rhs.m_Components[ r ] ) )
{
++r;
}
// In Both LHS & RHS
while ( l < nLhs && r < nRhs && m_Components[ l ] == rhs.m_Components[ r ] )
{
newComponents.AddToTail( m_Components[ l ] );
newWeights.AddToTail( m_Weights[ l ] );
++l;
++r;
}
}
m_Components.CopyArray( newComponents.Base(), newComponents.Count() );
m_Weights.CopyArray( newWeights.Base(), newWeights.Count() );
}
m_CompleteCount.Set( 0 );
m_bComplete.Set( false );
}