mirror of
https://github.com/thug1src/thug.git
synced 2024-11-30 12:06:44 +00:00
702 lines
21 KiB
C++
702 lines
21 KiB
C++
#if 0
|
|
|
|
//****************************************************************************
|
|
//* MODULE: Gel/Components
|
|
//* FILENAME: NearComponent.cpp
|
|
//* OWNER: Dave Cowling
|
|
//* CREATION DATE: 02/19/03
|
|
//****************************************************************************
|
|
|
|
#include <gel/components/nearcomponent.h>
|
|
|
|
#include <gel/object/compositeobject.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/script.h>
|
|
#include <gel/scripting/struct.h>
|
|
|
|
namespace Obj
|
|
{
|
|
|
|
sSweepPruneArray CNearComponent::m_sweep_prune_array[3] = { sSweepPruneArray( 0 ), sSweepPruneArray( 1 ), sSweepPruneArray( 2 ) };
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CBaseComponent* CNearComponent::s_create()
|
|
{
|
|
return static_cast< CBaseComponent* >( new CNearComponent );
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CNearComponent::CNearComponent() : CBaseComponent()
|
|
{
|
|
SetType( CRC_NEAR );
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CNearComponent::~CNearComponent()
|
|
{
|
|
// Remove from the axis arrays.
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
m_sweep_prune_array[axis].RemoveComponent( this );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNearComponent::InitFromStructure( Script::CStruct* pParams )
|
|
{
|
|
// Not sure where bounding box dimensions will come from.
|
|
m_untransformed_bbox.SetMin( Mth::Vector( -120.0f, -120.0f, -120.0f ));
|
|
m_untransformed_bbox.SetMax( Mth::Vector( 120.0f, 120.0f, 120.0f ));
|
|
|
|
// Obtain the position of the parent object, and build the transformed bounding box.
|
|
if( GetObject())
|
|
{
|
|
Mth::Vector t;
|
|
|
|
t = m_untransformed_bbox.GetMin() + GetObject()->GetPos();
|
|
m_transformed_bbox.SetMin( t );
|
|
|
|
t = m_untransformed_bbox.GetMax() + GetObject()->GetPos();
|
|
m_transformed_bbox.SetMax( t );
|
|
}
|
|
|
|
// Now add this component to the axis arrays.
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
m_sweep_prune_array[axis].InsertComponent( this );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNearComponent::RefreshFromStructure( Script::CStruct* pParams )
|
|
{
|
|
// Remove from axis arrays, then reinitialise.
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
m_sweep_prune_array[axis].RemoveComponent( this );
|
|
}
|
|
|
|
InitFromStructure( pParams );
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNearComponent::Update()
|
|
{
|
|
// Re-calculate the bounding box position.
|
|
if( GetObject())
|
|
{
|
|
Mth::Vector t;
|
|
|
|
t = m_untransformed_bbox.GetMin() + GetObject()->GetPos();
|
|
m_transformed_bbox.SetMin( t );
|
|
|
|
t = m_untransformed_bbox.GetMax() + GetObject()->GetPos();
|
|
m_transformed_bbox.SetMax( t );
|
|
|
|
// Resort the component.
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
m_sweep_prune_array[axis].ResortComponent( this );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CBaseComponent::EMemberFunctionResult CNearComponent::CallMemberFunction( uint32 Checksum, Script::CStruct* pParams, Script::CScript* pScript )
|
|
{
|
|
switch ( Checksum )
|
|
{
|
|
/*
|
|
// @script | DoSomething | does some functionality
|
|
case 0xbb4ad101: // DoSomething
|
|
DoSomething();
|
|
break;
|
|
|
|
// @script | ValueIsTrue | returns a boolean value
|
|
case 0x769260f7: // ValueIsTrue
|
|
{
|
|
return ValueIsTrue() ? CBaseComponent::MF_TRUE : CBaseComponent::MF_FALSE;
|
|
}
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
return CBaseComponent::MF_NOT_EXECUTED;
|
|
}
|
|
|
|
// the "default" case of the switch statement handles
|
|
// unrecognized functions; if we make it down here,
|
|
// that means that the component already handled it
|
|
// somehow
|
|
return CBaseComponent::MF_TRUE;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void CNearComponent::GetDebugInfo(Script::CStruct *p_info)
|
|
{
|
|
#ifdef __DEBUG_CODE__
|
|
Dbg_MsgAssert( p_info, ( "NULL p_info sent to CNearComponent::GetDebugInfo" ));
|
|
|
|
// Add any script components to the p_info structure,
|
|
// and they will be displayed in the script debugger (qdebug.exe)
|
|
// you will need to add the names to debugger_names.q, if they are not existing checksums
|
|
|
|
/* Example:
|
|
p_info->AddInteger("m_never_suspend",m_never_suspend);
|
|
p_info->AddFloat("m_suspend_distance",m_suspend_distance);
|
|
*/
|
|
|
|
// we call the base component's GetDebugInfo, so we can add info from the common base component
|
|
CBaseComponent::GetDebugInfo(p_info);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#define MAX_COMPONENTS_PER_WORKSPACE_ARRAY 64
|
|
static int perAxisIntersections[3];
|
|
static CNearComponent* perAxisWorkspace[3][MAX_COMPONENTS_PER_WORKSPACE_ARRAY];
|
|
static CNearComponent* combinedAxisWorkspace[MAX_COMPONENTS_PER_WORKSPACE_ARRAY];
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
int sSweepPruneArray::BinarySearchFirstBigger( float value )
|
|
{
|
|
int first_bigger = -1;
|
|
int l = 0;
|
|
int u = m_num_entries - 1;
|
|
while( l <= u )
|
|
{
|
|
int m = ( l + u ) / 2;
|
|
if( m_array[m].GetValue( m_axis ) <= value )
|
|
{
|
|
// x[m] <= t
|
|
l = m + 1;
|
|
}
|
|
else
|
|
{
|
|
// x[m] > t
|
|
first_bigger = m;
|
|
u = m - 1;
|
|
}
|
|
}
|
|
return first_bigger;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
int sSweepPruneArray::BinarySearchLastSmaller( float value )
|
|
{
|
|
int last_smaller = -1;
|
|
int l = 0;
|
|
int u = m_num_entries - 1;
|
|
while( l <= u )
|
|
{
|
|
int m = ( l + u ) / 2;
|
|
if( m_array[m].GetValue( m_axis ) <= value )
|
|
{
|
|
// x[m] <= t
|
|
last_smaller = m;
|
|
l = m + 1;
|
|
}
|
|
else
|
|
{
|
|
// x[m] > t
|
|
u = m - 1;
|
|
}
|
|
}
|
|
return last_smaller;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
int sSweepPruneArray::BuildCompositeIntersectingArray( void )
|
|
{
|
|
// Now build the composite array of intersections that appear in all three axis lists.
|
|
int final_intersections = 0;
|
|
int source, check1, check2;
|
|
|
|
// Use the smallest list to check against.
|
|
if(( perAxisIntersections[0] <= perAxisIntersections[1] ) && ( perAxisIntersections[0] <= perAxisIntersections[2] ))
|
|
{
|
|
source = 0;
|
|
check1 = 1;
|
|
check2 = 2;
|
|
}
|
|
else if(( perAxisIntersections[1] <= perAxisIntersections[0] ) && ( perAxisIntersections[1] <= perAxisIntersections[2] ))
|
|
{
|
|
source = 1;
|
|
check1 = 0;
|
|
check2 = 2;
|
|
}
|
|
else
|
|
{
|
|
source = 2;
|
|
check1 = 0;
|
|
check2 = 1;
|
|
}
|
|
|
|
for( int i = 0; i < perAxisIntersections[source]; ++i )
|
|
{
|
|
bool found;
|
|
|
|
// Is this intersection also in the first check list?
|
|
found = false;
|
|
for( int j = 0; j < perAxisIntersections[check1]; ++j )
|
|
{
|
|
if( perAxisWorkspace[source][i] == perAxisWorkspace[check1][j] )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it wasn't in the first check list, there's no intersection.
|
|
if( !found )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Is this intersection also in the second check list?
|
|
found = false;
|
|
for( int j = 0; j < perAxisIntersections[check2]; ++j )
|
|
{
|
|
if( perAxisWorkspace[source][i] == perAxisWorkspace[check2][j] )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it wasn't in the second check list, there's no intersection.
|
|
if( !found )
|
|
{
|
|
break;
|
|
}
|
|
|
|
// At this stage the intersection appeared in all three axis lists, so it is a valid intersection.
|
|
// As a final check, make sure it isn't already in the final list.
|
|
found = false;
|
|
for( int j = 0; j < final_intersections; ++j )
|
|
{
|
|
if( combinedAxisWorkspace[j] == perAxisWorkspace[source][i] )
|
|
{
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !found )
|
|
{
|
|
combinedAxisWorkspace[final_intersections] = perAxisWorkspace[source][i];
|
|
++final_intersections;
|
|
}
|
|
}
|
|
return final_intersections;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CNearComponent** CNearComponent::GetIntersectingNearComponents( Mth::Vector &bbmin, Mth::Vector &bbmax, int *p_num_intersecting )
|
|
{
|
|
// Zero axis intersection count array.
|
|
perAxisIntersections[0] = perAxisIntersections[1] = perAxisIntersections[2] = 0;
|
|
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
// Find the start index.
|
|
int start_index = m_sweep_prune_array[axis].BinarySearchFirstBigger( bbmin[axis] );
|
|
if( start_index == -1 )
|
|
{
|
|
// Nothing was found, therefore there can be no intersections.
|
|
*p_num_intersecting = 0;
|
|
return NULL;
|
|
}
|
|
|
|
// Find the end index.
|
|
int end_index = m_sweep_prune_array[axis].BinarySearchLastSmaller( bbmax[axis] );
|
|
if( end_index == -1 )
|
|
{
|
|
// Nothing was found, therefore there can be no intersections.
|
|
*p_num_intersecting = 0;
|
|
return NULL;
|
|
}
|
|
|
|
Dbg_Assert( end_index > start_index );
|
|
|
|
// Build up the workspace array for this axis.
|
|
int intersections_for_this_axis = 0;
|
|
for( int i = start_index; i <= end_index; ++i )
|
|
{
|
|
// Don't want to include the calling component in the list.
|
|
if( m_sweep_prune_array[axis].m_array[i].mp_component != this )
|
|
{
|
|
perAxisWorkspace[axis][intersections_for_this_axis++] = m_sweep_prune_array[axis].m_array[i].mp_component;
|
|
}
|
|
}
|
|
|
|
// If we found no intersections for this axis, there can be no components that intersect.
|
|
if( intersections_for_this_axis == 0 )
|
|
{
|
|
*p_num_intersecting = 0;
|
|
return NULL;
|
|
}
|
|
|
|
// Store off the number of intersections for this axis.
|
|
perAxisIntersections[axis] = intersections_for_this_axis;
|
|
|
|
}
|
|
|
|
// Build the composite array.
|
|
int final_intersections = sSweepPruneArray::BuildCompositeIntersectingArray();
|
|
|
|
*p_num_intersecting = final_intersections;
|
|
return ( final_intersections > 0 ) ? &combinedAxisWorkspace[0] : NULL;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
CNearComponent** CNearComponent::GetIntersectingNearComponents( int *p_num_intersecting )
|
|
{
|
|
// Zero axis intersection count array.
|
|
perAxisIntersections[0] = perAxisIntersections[1] = perAxisIntersections[2] = 0;
|
|
|
|
// Build up each workspace array.
|
|
for( int axis = 0; axis < 3; ++axis )
|
|
{
|
|
int i;
|
|
for( i = 0; i < m_sweep_prune_array[axis].m_num_entries; ++i )
|
|
{
|
|
if( m_sweep_prune_array[axis].m_array[i].mp_component == this )
|
|
{
|
|
// We have found the start of the span for this component.
|
|
Dbg_Assert( m_sweep_prune_array[axis].m_array[i].m_min_max == 0 );
|
|
++i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now add any other components we come across before we hit the end of the span.
|
|
while(( i < m_sweep_prune_array[axis].m_num_entries ) && ( m_sweep_prune_array[axis].m_array[i].mp_component != this ))
|
|
{
|
|
perAxisWorkspace[axis][perAxisIntersections[axis]] = m_sweep_prune_array[axis].m_array[i].mp_component;
|
|
++perAxisIntersections[axis];
|
|
++i;
|
|
}
|
|
|
|
// If we found no intersections for this axis, there can be no components that intersect.
|
|
if( perAxisIntersections[axis] == 0 )
|
|
{
|
|
*p_num_intersecting = 0;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Build the composite array.
|
|
int final_intersections = sSweepPruneArray::BuildCompositeIntersectingArray();
|
|
|
|
*p_num_intersecting = final_intersections;
|
|
return ( final_intersections > 0 ) ? &combinedAxisWorkspace[0] : NULL;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneEntry::SetValues( void )
|
|
{
|
|
Mth::Vector v = ( m_min_max ) ? mp_component->GetMax() : mp_component->GetMin();
|
|
m_value[0] = v[0];
|
|
m_value[1] = v[1];
|
|
m_value[2] = v[2];
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
sSweepPruneArray::sSweepPruneArray( int axis )
|
|
{
|
|
m_axis = axis;
|
|
m_num_entries = 0;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
sSweepPruneArray::~sSweepPruneArray( void )
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneArray::PushUp( int index )
|
|
{
|
|
Dbg_MsgAssert( m_num_entries < MAX_SWEEP_PRUNE_ENTRIES_PER_AXIS, ( "CNearComponent::SweepPruneList overflow" ));
|
|
|
|
// All array entries from index (inclusive) upwards are moved up one position.
|
|
for( int i = m_num_entries - 1; i >= index; --i )
|
|
{
|
|
m_array[i + 1] = m_array[i];
|
|
}
|
|
++m_num_entries;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneArray::PullDown( int index )
|
|
{
|
|
Dbg_MsgAssert( m_num_entries > 0, ( "CNearComponent::SweepPruneList underflow" ));
|
|
|
|
// All array entries from index (inclusive) upwards are moved down one position.
|
|
for( int i = index; i < ( m_num_entries - 1 ); ++i )
|
|
{
|
|
m_array[i] = m_array[i + 1];
|
|
}
|
|
--m_num_entries;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneArray::ResortComponent( CNearComponent *p_component )
|
|
{
|
|
// Does a simple check to see whether the component is still in the correct order.
|
|
// If it isn't, sorting is applied.
|
|
|
|
// Check min first.
|
|
int i;
|
|
for( i = 0; i < m_num_entries; ++i )
|
|
{
|
|
if( m_array[i].mp_component == p_component )
|
|
{
|
|
// This should be the min entry.
|
|
Dbg_Assert( m_array[i].m_min_max == 0 );
|
|
|
|
// Set the new min value.
|
|
m_array[i].SetValues();
|
|
|
|
// Check this is bigger than or equal to the previous value, if there is one.
|
|
while(( i > 0 ) && ( m_array[i].GetValue( m_axis ) < m_array[i - 1].GetValue( m_axis )))
|
|
{
|
|
// Move this entry down in the array.
|
|
sSweepPruneEntry swap = m_array[i];
|
|
m_array[i] = m_array[i - 1];
|
|
m_array[i - 1] = swap;
|
|
--i;
|
|
}
|
|
|
|
// Check this is smaller than or equal to the next value, if there is one.
|
|
while(( i < ( m_num_entries - 1)) && ( m_array[i].GetValue( m_axis ) > m_array[i + 1].GetValue( m_axis )))
|
|
{
|
|
// Move this entry up in the array.
|
|
sSweepPruneEntry swap = m_array[i];
|
|
m_array[i] = m_array[i + 1];
|
|
m_array[i + 1] = swap;
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now check max.
|
|
++i;
|
|
for( ; i < m_num_entries; ++i )
|
|
{
|
|
if( m_array[i].mp_component == p_component )
|
|
{
|
|
// This should be the max entry.
|
|
Dbg_Assert( m_array[i].m_min_max == 1 );
|
|
|
|
// Set the new max value.
|
|
m_array[i].SetValues();
|
|
|
|
// Check this is bigger than or equal to the previous value, if there is one.
|
|
while(( i > 0 ) && ( m_array[i].GetValue( m_axis ) < m_array[i - 1].GetValue( m_axis )))
|
|
{
|
|
// Move this entry down in the array.
|
|
sSweepPruneEntry swap = m_array[i];
|
|
m_array[i] = m_array[i - 1];
|
|
m_array[i - 1] = swap;
|
|
--i;
|
|
}
|
|
|
|
// Check this is smaller than or equal to the next value, if there is one.
|
|
while(( i < ( m_num_entries - 1)) && ( m_array[i].GetValue( m_axis ) > m_array[i + 1].GetValue( m_axis )))
|
|
{
|
|
// Move this entry up in the array.
|
|
sSweepPruneEntry swap = m_array[i];
|
|
m_array[i] = m_array[i + 1];
|
|
m_array[i + 1] = swap;
|
|
++i;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneArray::InsertComponent( CNearComponent *p_component )
|
|
{
|
|
float axis_min = p_component->GetMin()[m_axis];
|
|
float axis_max = p_component->GetMax()[m_axis];
|
|
|
|
// Scan through until we find an entry that is bigger than the minimum for this axis, or we come to the end of the list.
|
|
for( int i = 0; i <= m_num_entries; ++i )
|
|
{
|
|
if(( i == m_num_entries ) || ( m_array[i].mp_component->GetMin()[m_axis] > axis_min ))
|
|
{
|
|
// Insert this entry here.
|
|
PushUp( i );
|
|
m_array[i].m_min_max = 0;
|
|
m_array[i].mp_component = p_component;
|
|
|
|
// Set the new min value.
|
|
m_array[i].SetValues();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Now scan through until we find an entry that is bigger than the maximum for this axis, or we come to the end of the list.
|
|
for( int i = 0; i <= m_num_entries; ++i )
|
|
{
|
|
if(( i == m_num_entries ) || ( m_array[i].mp_component->GetMax()[m_axis] > axis_max ))
|
|
{
|
|
// Insert this entry here.
|
|
PushUp( i );
|
|
m_array[i].m_min_max = 1;
|
|
m_array[i].mp_component = p_component;
|
|
|
|
// Set the new min value.
|
|
m_array[i].SetValues();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
void sSweepPruneArray::RemoveComponent( CNearComponent *p_component )
|
|
{
|
|
// The component should appear twice in the list.
|
|
for( int p = 0; p < 2; ++p )
|
|
{
|
|
// Scan through until we find this entry.
|
|
for( int i = 0; i < m_num_entries; ++i )
|
|
{
|
|
if( m_array[i].mp_component == p_component )
|
|
{
|
|
// Remove this entry.
|
|
PullDown( i );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|