mirror of
https://github.com/thug1src/thug.git
synced 2024-12-02 12:56:45 +00:00
2240 lines
65 KiB
C++
2240 lines
65 KiB
C++
|
/*****************************************************************************
|
||
|
** **
|
||
|
** Neversoft Entertainment. **
|
||
|
** **
|
||
|
** Copyright (C) 1999 - All Rights Reserved **
|
||
|
** **
|
||
|
******************************************************************************
|
||
|
** **
|
||
|
** Project: PS2 **
|
||
|
** **
|
||
|
** Module: Nx **
|
||
|
** **
|
||
|
** File name: gel\collision\collide.cpp **
|
||
|
** **
|
||
|
** Created by: 02/20/02 - grj **
|
||
|
** **
|
||
|
** Description: **
|
||
|
** **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** Includes **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
#include <core/defines.h>
|
||
|
|
||
|
#include <gel/collision/collision.h>
|
||
|
#include <gel/collision/colltridata.h>
|
||
|
|
||
|
#include <gfx/nx.h>
|
||
|
#include <gfx/nxflags.h> // for face flag stuff
|
||
|
#include <gfx/debuggfx.h>
|
||
|
|
||
|
#include <sk/engine/feeler.h>
|
||
|
|
||
|
|
||
|
// For debugging rendering
|
||
|
#include <gfx/nxviewman.h>
|
||
|
#include <gfx/camera.h>
|
||
|
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
#include <gfx/ngps/nx/line.h>
|
||
|
#include <gfx/ngps/p_nxsector.h>
|
||
|
#include <gfx/ngps/nx/geomnode.h>
|
||
|
#include <gfx/ngps/nx/render.h>
|
||
|
namespace NxPs2
|
||
|
{
|
||
|
bool TestSphereAgainstOccluders( Mth::Vector *p_center, float radius, uint32 meshes = 1 );
|
||
|
bool IsInFrame(Mth::Vector ¢er, float radius);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
#include <gfx/ngc/nx/scene.h>
|
||
|
#include <gfx/ngc/p_nxscene.h>
|
||
|
#endif // __PLAT_NGC__
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
** DBG Information **
|
||
|
*****************************************************************************/
|
||
|
|
||
|
|
||
|
|
||
|
namespace Nx
|
||
|
{
|
||
|
|
||
|
|
||
|
FaceIndex CCollObjTriData::s_face_index_buffer[MAX_FACE_INDICIES];
|
||
|
FaceIndex CCollObjTriData::s_seq_face_index_buffer[MAX_FACE_INDICIES] = { 0xFFFF }; // Set to uninitialized
|
||
|
uint CCollObjTriData::s_num_face_indicies;
|
||
|
|
||
|
const uint CCollObjTriData::s_max_face_per_leaf = 20; // maximum number faces per leaf
|
||
|
const uint CCollObjTriData::s_max_tree_levels = 7; // maximum number of levels in a tree
|
||
|
|
||
|
#define USE_BSP_CLONE
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
CCollObjTriData::CCollObjTriData()
|
||
|
{
|
||
|
#ifdef __PLAT_NGC__
|
||
|
mp_cloned_vert_pos = NULL;
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
CCollObjTriData::~CCollObjTriData()
|
||
|
{
|
||
|
// Clones are the only types that should make it here
|
||
|
// Remove vertices
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if ( mp_cloned_vert_pos )
|
||
|
{
|
||
|
delete [] mp_cloned_vert_pos;
|
||
|
}
|
||
|
#else
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
if (mp_float_vert)
|
||
|
{
|
||
|
delete [] mp_float_vert;
|
||
|
}
|
||
|
#else
|
||
|
if (mp_vert_pos)
|
||
|
{
|
||
|
delete[] mp_vert_pos;
|
||
|
}
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
#endif // __PLAT_NGC__
|
||
|
if (mp_intensity)
|
||
|
{
|
||
|
delete[] mp_intensity;
|
||
|
}
|
||
|
|
||
|
// Remove faces
|
||
|
if (mp_faces)
|
||
|
{
|
||
|
if (m_use_face_small)
|
||
|
{
|
||
|
delete[] mp_face_small;
|
||
|
} else{
|
||
|
delete[] mp_faces;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DeleteBSPTree();
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CCollObjTriData::InitCollObjTriData(CScene * p_scene, void *p_base_vert_addr, void *p_base_intensity_addr,
|
||
|
void *p_base_face_addr, void *p_base_node_addr, void *p_base_face_idx_addr)
|
||
|
{
|
||
|
// Set base addr
|
||
|
#ifdef __PLAT_NGC__
|
||
|
NxNgc::sScene *p_engine_scene = ( static_cast<CNgcScene*>( p_scene ))->GetEngineScene();
|
||
|
mp_raw_vert_pos = (NsVector*)p_engine_scene->mp_pos_pool;
|
||
|
mp_intensity = (unsigned char *) ((int) p_base_vert_addr + (int)mp_intensity);
|
||
|
mp_cloned_vert_pos = NULL;
|
||
|
#else
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
// Get indexes
|
||
|
int start_vert_pos_offset = (int) mp_float_vert;
|
||
|
int start_intensity_index = (int) mp_intensity;
|
||
|
|
||
|
// Find first element
|
||
|
mp_float_vert = (SFloatVert *) ((int) p_base_vert_addr + start_vert_pos_offset);
|
||
|
mp_intensity = (uint8 *) p_base_intensity_addr;
|
||
|
mp_intensity += start_intensity_index;
|
||
|
#else
|
||
|
// Get indexes
|
||
|
int start_vert_pos_offset = (int) mp_vert_pos;
|
||
|
|
||
|
// Find first element
|
||
|
mp_vert_pos = (Mth::Vector *) ((int) p_base_vert_addr + start_vert_pos_offset);
|
||
|
|
||
|
mp_intensity = NULL;
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
#endif // __PLAT_NGC__
|
||
|
|
||
|
mp_faces = (SFace *)((int) mp_faces + (int) p_base_face_addr);
|
||
|
|
||
|
//Dbg_Message ( "Object has %d verts sizeof %d", m_num_verts, sizeof(SReadVertex));
|
||
|
//Dbg_Message ( "Object has %d faces sizeof %d", m_num_faces, sizeof(SReadFace) );
|
||
|
#ifndef FIXED_POINT_VERTICES
|
||
|
Dbg_Assert(!m_use_fixed_verts)
|
||
|
#endif
|
||
|
|
||
|
// Init BSP tree
|
||
|
mp_bsp_tree = (CCollBSPNode *)((int) mp_bsp_tree + (int) p_base_node_addr);
|
||
|
s_init_tree(mp_bsp_tree, p_base_node_addr, p_base_face_idx_addr);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
CCollBSPNode::CCollBSPNode()
|
||
|
{
|
||
|
//m_node.m_split_axis = 0;
|
||
|
m_node.m_split_point = 0; // This is so we know it is a node
|
||
|
m_node.m_children.Init();
|
||
|
//mp_greater_branch = NULL;
|
||
|
}
|
||
|
|
||
|
CCollBSPNode::~CCollBSPNode()
|
||
|
{
|
||
|
#ifdef USE_BSP_CLONE
|
||
|
// Since the cloned BSP tree is allocated as one big buffer, these calls shouldn't
|
||
|
// be necessary.
|
||
|
return;
|
||
|
|
||
|
#else
|
||
|
Dbg_MsgAssert(IsNode(), ("Called ~CCollBSPNode() on CCollBSPLeaf()"));
|
||
|
|
||
|
Dbg_MsgAssert(0, ("Only cloned collision should get to the BSP destructor"));
|
||
|
#endif // USE_BSP_CLONE
|
||
|
|
||
|
if (GetLessBranch())
|
||
|
{
|
||
|
delete GetLessBranch();
|
||
|
}
|
||
|
|
||
|
if (GetGreaterBranch())
|
||
|
{
|
||
|
delete GetGreaterBranch();
|
||
|
}
|
||
|
|
||
|
if (GetFaceIndexArray())
|
||
|
{
|
||
|
delete GetFaceIndexArray();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollBSPNode::SetSplitAxis(int axis)
|
||
|
{
|
||
|
Dbg_Assert(IsNode());
|
||
|
|
||
|
m_node.m_split_point = m_node.m_split_point & ~((1 << NUM_AXIS_BITS) - 1); // Clear out old axis
|
||
|
m_node.m_split_point = m_node.m_split_point | (axis & ((1 << NUM_AXIS_BITS) - 1));
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
// Garrett: This is an unconventional way of cloning the data. We are assuming that all the
|
||
|
// tree nodes are in one contiguous block of memory. I normally wouldn't write code like
|
||
|
// this, but we need to avoid lots of small allocations.
|
||
|
CCollBSPNode * CCollBSPNode::clone(bool instance)
|
||
|
{
|
||
|
Dbg_MsgAssert(!instance, ("CCollBSPNode::clone() with instances not implemented yet"));
|
||
|
//Dbg_MsgAssert(IsNode(), ("Called CCollBSPNode::clone() on CCollBSPLeaf()"));
|
||
|
|
||
|
// So that we don't make lots of little allocations, allocate the whole BSP array at once
|
||
|
int num_nodes = count_bsp_nodes();
|
||
|
int num_face_indices = count_bsp_face_indices();
|
||
|
if (num_nodes > 0)
|
||
|
{
|
||
|
Dbg_MsgAssert(num_face_indices, ("Didn't find any face indices in the BSP tree"));
|
||
|
FaceIndex * p_orig_face_index_array = find_bsp_face_index_array_start();
|
||
|
|
||
|
CCollBSPNode * p_new_bsp_array = new CCollBSPNode[num_nodes];
|
||
|
FaceIndex * p_new_face_index_array = new FaceIndex[num_face_indices];
|
||
|
|
||
|
// Just memcpy it first, since we know the source tree is in an array
|
||
|
memcpy(p_new_bsp_array, this, num_nodes * sizeof(CCollBSPNode));
|
||
|
memcpy(p_new_face_index_array, p_orig_face_index_array, num_face_indices * sizeof(FaceIndex));
|
||
|
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
// Look through new bsp array that still has the old face index pointers in it.
|
||
|
for (int node_idx = 0; node_idx < num_nodes; node_idx++)
|
||
|
{
|
||
|
if (p_new_bsp_array[node_idx].IsLeaf())
|
||
|
{
|
||
|
Dbg_MsgAssert(p_orig_face_index_array <= p_new_bsp_array[node_idx].GetFaceIndexArray(), ("find_bsp_face_index_array_start() failed"));
|
||
|
}
|
||
|
}
|
||
|
#endif // __NOPT_ASSERT__
|
||
|
|
||
|
// Now adjust the pointers by finding the differences
|
||
|
int node_address_diff = (int) p_new_bsp_array - (int) this;
|
||
|
int face_address_diff = (int) p_new_face_index_array - (int) p_orig_face_index_array;
|
||
|
for (int i = 0; i < num_nodes; i++)
|
||
|
{
|
||
|
if (p_new_bsp_array[i].IsNode())
|
||
|
{
|
||
|
// Adjust branch pointers
|
||
|
p_new_bsp_array[i].m_node.m_children.SetBasePointer((CCollBSPNode *)((int) p_new_bsp_array[i].m_node.m_children.GetBasePointer() + node_address_diff));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Adjust face index pointer
|
||
|
p_new_bsp_array[i].m_leaf.mp_face_idx_array = (FaceIndex *) ((int) p_new_bsp_array[i].m_leaf.mp_face_idx_array + face_address_diff);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return p_new_bsp_array;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int CCollBSPNode::count_bsp_nodes()
|
||
|
{
|
||
|
if (IsLeaf())
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return 1 + GetLessBranch()->count_bsp_nodes() + GetGreaterBranch()->count_bsp_nodes();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
int CCollBSPNode::count_bsp_face_indices()
|
||
|
{
|
||
|
if (IsLeaf())
|
||
|
{
|
||
|
return m_leaf.m_num_faces;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return GetLessBranch()->count_bsp_face_indices() + GetGreaterBranch()->count_bsp_face_indices();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
FaceIndex * CCollBSPNode::find_bsp_face_index_array_start()
|
||
|
{
|
||
|
if (IsLeaf())
|
||
|
{
|
||
|
return m_leaf.mp_face_idx_array;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FaceIndex *p_index1 = GetLessBranch()->find_bsp_face_index_array_start();
|
||
|
FaceIndex *p_index2 = GetGreaterBranch()->find_bsp_face_index_array_start();
|
||
|
|
||
|
if (p_index1 < p_index2)
|
||
|
return p_index1;
|
||
|
else
|
||
|
return p_index2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollBSPNode::CCollBSPChildren::SetLeftGreater(bool greater)
|
||
|
{
|
||
|
if (greater)
|
||
|
{
|
||
|
m_left_child_and_flags |= mLEFT_IS_GREATER;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_left_child_and_flags &= ~mLEFT_IS_GREATER;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollBSPNode::translate(const Mth::Vector & delta_trans)
|
||
|
{
|
||
|
// Translate node
|
||
|
if (IsNode())
|
||
|
{
|
||
|
int axis = GetSplitAxis();
|
||
|
|
||
|
SetFSplitPoint(GetFSplitPoint() + delta_trans[axis]);
|
||
|
|
||
|
// Traverse the tree
|
||
|
GetLessBranch()->translate(delta_trans);
|
||
|
GetGreaterBranch()->translate(delta_trans);
|
||
|
}
|
||
|
|
||
|
// Leaf does nothing
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollBSPNode::rotate_y(const Mth::Vector & world_origin, Mth::ERot90 rot_y, bool root_node)
|
||
|
{
|
||
|
// Take it to the origin
|
||
|
if (root_node)
|
||
|
{
|
||
|
translate(-world_origin);
|
||
|
}
|
||
|
|
||
|
// Rotate node
|
||
|
if (IsNode())
|
||
|
{
|
||
|
int axis = GetSplitAxis();
|
||
|
|
||
|
if (axis != Y) // Y won't change
|
||
|
{
|
||
|
int other_axis = (axis == X) ? Z : X; // So we know what axis we potentially flip to
|
||
|
|
||
|
switch (rot_y)
|
||
|
{
|
||
|
case Mth::ROT_0:
|
||
|
break;
|
||
|
|
||
|
case Mth::ROT_90:
|
||
|
if (axis == X)
|
||
|
{
|
||
|
SetSplitPoint(-GetSplitPoint());
|
||
|
m_node.m_children.SetLeftGreater(!m_node.m_children.IsLeftGreater());
|
||
|
}
|
||
|
SetSplitAxis(other_axis);
|
||
|
break;
|
||
|
|
||
|
case Mth::ROT_180:
|
||
|
SetSplitPoint(-GetSplitPoint());
|
||
|
m_node.m_children.SetLeftGreater(!m_node.m_children.IsLeftGreater());
|
||
|
break;
|
||
|
|
||
|
case Mth::ROT_270:
|
||
|
if (axis == Z)
|
||
|
{
|
||
|
SetSplitPoint(-GetSplitPoint());
|
||
|
m_node.m_children.SetLeftGreater(!m_node.m_children.IsLeftGreater());
|
||
|
}
|
||
|
SetSplitAxis(other_axis);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Dbg_MsgAssert(0, ("CCollBSPNode::rotate_y() out of range: %d", rot_y));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Traverse the tree
|
||
|
GetLessBranch()->rotate_y(world_origin, rot_y, false);
|
||
|
GetGreaterBranch()->rotate_y(world_origin, rot_y, false);
|
||
|
}
|
||
|
// Leaf does nothing
|
||
|
|
||
|
// Put it back
|
||
|
if (root_node)
|
||
|
{
|
||
|
translate(world_origin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollBSPNode::scale(const Mth::Vector & world_origin, const Mth::Vector & scale, bool root_node)
|
||
|
{
|
||
|
// Take it to the origin
|
||
|
if (root_node)
|
||
|
{
|
||
|
translate(-world_origin);
|
||
|
}
|
||
|
|
||
|
// Scale node
|
||
|
if (IsNode())
|
||
|
{
|
||
|
int axis = GetSplitAxis();
|
||
|
|
||
|
SetFSplitPoint(GetFSplitPoint() * scale[axis]);
|
||
|
|
||
|
// Traverse the tree
|
||
|
GetLessBranch()->scale(world_origin, scale, false);
|
||
|
GetGreaterBranch()->scale(world_origin, scale, false);
|
||
|
}
|
||
|
// Leaf does nothing
|
||
|
|
||
|
// Put it back
|
||
|
if (root_node)
|
||
|
{
|
||
|
translate(world_origin);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CCollObjTriData::s_init_tree(CCollBSPNode *p_tree, void *p_base_node_addr, void *p_base_face_idx_addr)
|
||
|
{
|
||
|
if (p_tree->IsLeaf())
|
||
|
{
|
||
|
// Set face index array pointer
|
||
|
int face_idx = (int) p_tree->m_leaf.mp_face_idx_array;
|
||
|
p_tree->m_leaf.mp_face_idx_array = (FaceIndex *) p_base_face_idx_addr;
|
||
|
p_tree->m_leaf.mp_face_idx_array += face_idx;
|
||
|
|
||
|
//Dbg_Assert(((int) p_leaf->mp_less_branch) == -1);
|
||
|
//Dbg_Assert(((int) p_leaf->mp_greater_branch) == -1);
|
||
|
|
||
|
//p_leaf->mp_less_branch = NULL;
|
||
|
//p_leaf->mp_greater_branch = NULL;
|
||
|
} else {
|
||
|
Dbg_MsgAssert(p_tree->GetSplitAxis() < 3, ("BSP split axis is %d", p_tree->GetSplitAxis()));
|
||
|
// Set branch pointers
|
||
|
p_tree->m_node.m_children.SetBasePointer((CCollBSPNode *)((int) p_tree->m_node.m_children.GetBasePointer() + (int) p_base_node_addr));
|
||
|
|
||
|
// And init branches
|
||
|
s_init_tree(p_tree->GetLessBranch(), p_base_node_addr, p_base_face_idx_addr);
|
||
|
s_init_tree(p_tree->GetGreaterBranch(), p_base_node_addr, p_base_face_idx_addr);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CCollObjTriData::InitBSPTree()
|
||
|
{
|
||
|
// Initialize sequence face index list, if not done yet
|
||
|
if (s_seq_face_index_buffer[0] != 0)
|
||
|
{
|
||
|
for (int i = 0; i < MAX_FACE_INDICIES; i++)
|
||
|
{
|
||
|
s_seq_face_index_buffer[i] = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Dbg_MsgAssert(m_num_faces < MAX_FACE_INDICIES, ("Too many polys in a collision sector: %d", m_num_faces));
|
||
|
|
||
|
//Dbg_MsgAssert(0, ("Node size %d; Leaf size %d", sizeof(CCollBSPNode), sizeof(CCollBSPLeaf)));
|
||
|
|
||
|
// Create the tree
|
||
|
// Don't use this since it is pip-ed
|
||
|
//mp_bsp_tree = create_bsp_tree(m_bbox, s_seq_face_index_buffer, m_num_faces);
|
||
|
|
||
|
return mp_bsp_tree != NULL;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CCollObjTriData::DeleteBSPTree()
|
||
|
{
|
||
|
#ifndef USE_BSP_CLONE
|
||
|
// Don't use this since it is pip-ed
|
||
|
return false;
|
||
|
|
||
|
Dbg_MsgAssert(0, ("This should only be called on clones"));
|
||
|
#endif
|
||
|
|
||
|
if (mp_bsp_tree)
|
||
|
{
|
||
|
#ifndef USE_BSP_CLONE
|
||
|
// Recursively delete
|
||
|
delete mp_bsp_tree;
|
||
|
#else
|
||
|
// Delete as array
|
||
|
FaceIndex *p_face_index_array = mp_bsp_tree->find_bsp_face_index_array_start();
|
||
|
if (p_face_index_array)
|
||
|
{
|
||
|
delete [] p_face_index_array;
|
||
|
}
|
||
|
delete [] mp_bsp_tree;
|
||
|
#endif
|
||
|
mp_bsp_tree = NULL;
|
||
|
|
||
|
return true;
|
||
|
} else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
bool CCollObjTriData::calc_split_faces(uint axis, float axis_distance, FaceIndex *p_face_indexes,
|
||
|
uint num_faces, uint & less_faces, uint & greater_faces,
|
||
|
FaceIndex *p_less_face_indexes, FaceIndex *p_greater_face_indexes)
|
||
|
{
|
||
|
less_faces = greater_faces = 0;
|
||
|
|
||
|
for (uint i = 0; i < num_faces; i++)
|
||
|
{
|
||
|
bool less = false, greater = false;
|
||
|
|
||
|
// Check the face
|
||
|
for (uint j = 0; j < 3; j++)
|
||
|
{
|
||
|
uint vidx = GetFaceVertIndex(i, j);
|
||
|
#if defined(FIXED_POINT_VERTICES) || defined(__PLAT_NGC__)
|
||
|
if (GetRawVertexPos(vidx)[axis] < axis_distance)
|
||
|
{
|
||
|
less = true;
|
||
|
} else if (GetRawVertexPos(vidx)[axis] >= axis_distance)
|
||
|
{
|
||
|
greater = true;
|
||
|
}
|
||
|
#else
|
||
|
if (mp_vert_pos[vidx][axis] < axis_distance)
|
||
|
{
|
||
|
less = true;
|
||
|
} else if (mp_vert_pos[vidx][axis] >= axis_distance)
|
||
|
{
|
||
|
greater = true;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
Dbg_Assert(less || greater);
|
||
|
|
||
|
// Increment counts and possibly put in new array
|
||
|
if (less)
|
||
|
{
|
||
|
if (p_less_face_indexes)
|
||
|
{
|
||
|
p_less_face_indexes[less_faces] = p_face_indexes[i];
|
||
|
}
|
||
|
less_faces++;
|
||
|
}
|
||
|
if (greater)
|
||
|
{
|
||
|
if (p_greater_face_indexes)
|
||
|
{
|
||
|
p_greater_face_indexes[greater_faces] = p_face_indexes[i];
|
||
|
}
|
||
|
greater_faces++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
#if 0
|
||
|
CCollBSPLeaf * CCollObjTriData::create_bsp_leaf(FaceIndex *p_face_indexes, uint num_faces)
|
||
|
{
|
||
|
CCollBSPLeaf *p_bsp_leaf = new CCollBSPLeaf;
|
||
|
p_bsp_leaf->m_split_axis = -1;
|
||
|
p_bsp_leaf->mp_less_branch = NULL;
|
||
|
p_bsp_leaf->mp_greater_branch = NULL;
|
||
|
|
||
|
// Make new array in BottomUp memory
|
||
|
p_bsp_leaf->m_num_faces = num_faces;
|
||
|
p_bsp_leaf->mp_face_idx_array = new FaceIndex[num_faces];
|
||
|
for (uint i = 0; i < num_faces; i++)
|
||
|
{
|
||
|
p_bsp_leaf->mp_face_idx_array[i] = p_face_indexes[i];
|
||
|
}
|
||
|
|
||
|
return p_bsp_leaf;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
CCollBSPNode * CCollObjTriData::create_bsp_tree(const Mth::CBBox & bbox, FaceIndex *p_face_indexes, uint num_faces, uint level)
|
||
|
{
|
||
|
if ((num_faces <= s_max_face_per_leaf) || (level == s_max_tree_levels)) // Check if this should be a leaf
|
||
|
{
|
||
|
return create_bsp_leaf(p_face_indexes, num_faces);
|
||
|
} else { // Create Node
|
||
|
|
||
|
// Find initial splits on the three axis
|
||
|
Mth::Vector mid_width((bbox.GetMax() - bbox.GetMin()) * 0.5f);
|
||
|
Mth::Vector mid_split(mid_width + bbox.GetMin());
|
||
|
|
||
|
// Find the weighting of the three potential splits
|
||
|
uint less_faces[3], greater_faces[3];
|
||
|
calc_split_faces(X, mid_split[X], p_face_indexes, num_faces, less_faces[X], greater_faces[X]);
|
||
|
calc_split_faces(Y, mid_split[Y], p_face_indexes, num_faces, less_faces[Y], greater_faces[Y]);
|
||
|
calc_split_faces(Z, mid_split[Z], p_face_indexes, num_faces, less_faces[Z], greater_faces[Z]);
|
||
|
|
||
|
// Figure out best split
|
||
|
int best_axis = -1;
|
||
|
float best_diff = -1;
|
||
|
const int duplicate_threshold = (num_faces * 7) / 10; // tunable
|
||
|
for (uint axis = X; axis <= Z; axis++)
|
||
|
{
|
||
|
float new_diff = (float)fabs((float)(less_faces[axis] - greater_faces[axis]));
|
||
|
int duplicates = less_faces[axis] + greater_faces[axis] - num_faces;
|
||
|
|
||
|
if (duplicates >= duplicate_threshold)
|
||
|
continue;
|
||
|
|
||
|
new_diff += duplicates; // tunable
|
||
|
new_diff /= mid_width[axis]; // tunable
|
||
|
|
||
|
if ((best_axis < 0) || (new_diff < best_diff))
|
||
|
{
|
||
|
best_axis = axis;
|
||
|
best_diff = new_diff;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (best_axis < 0) // Couldn't make a good split, give up
|
||
|
{
|
||
|
return create_bsp_leaf(p_face_indexes, num_faces);
|
||
|
}
|
||
|
|
||
|
// We need to allocate temp arrays
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
|
||
|
|
||
|
// Allocate new temp arrays for the face indexes
|
||
|
FaceIndex *p_less_face_indexes = new FaceIndex[less_faces[best_axis]];
|
||
|
FaceIndex *p_greater_face_indexes = new FaceIndex[greater_faces[best_axis]];
|
||
|
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
// Now fill in the array
|
||
|
calc_split_faces(best_axis, mid_split[best_axis], p_face_indexes, num_faces,
|
||
|
less_faces[best_axis], greater_faces[best_axis],
|
||
|
p_less_face_indexes, p_greater_face_indexes);
|
||
|
|
||
|
// And the new bboxes
|
||
|
Mth::CBBox less_bbox(bbox), greater_bbox(bbox);
|
||
|
Mth::Vector less_max = less_bbox.GetMax();
|
||
|
Mth::Vector greater_min = greater_bbox.GetMin();
|
||
|
less_max[best_axis] = mid_split[best_axis];
|
||
|
greater_min[best_axis] = mid_split[best_axis];
|
||
|
less_bbox.SetMax(less_max);
|
||
|
greater_bbox.SetMin(greater_min);
|
||
|
|
||
|
// And now calculate the branches
|
||
|
CCollBSPNode *p_bsp_tree = new CCollBSPNode;
|
||
|
p_bsp_tree->m_split_axis = best_axis;
|
||
|
p_bsp_tree->m_split_point = mid_split[best_axis];
|
||
|
p_bsp_tree->mp_less_branch = create_bsp_tree(less_bbox, p_less_face_indexes, less_faces[best_axis], level + 1);
|
||
|
p_bsp_tree->mp_greater_branch = create_bsp_tree(greater_bbox, p_greater_face_indexes, greater_faces[best_axis], level + 1);
|
||
|
|
||
|
// Free temp arrays
|
||
|
delete p_less_face_indexes;
|
||
|
delete p_greater_face_indexes;
|
||
|
|
||
|
return p_bsp_tree;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::find_faces(CCollBSPNode *p_bsp_node, const Mth::CBBox & bbox)
|
||
|
{
|
||
|
int axis = p_bsp_node->GetSplitAxis();
|
||
|
|
||
|
if (axis == 3) // Leaf
|
||
|
{
|
||
|
//CCollBSPLeaf *p_bsp_leaf = static_cast<CCollBSPLeaf *>(p_bsp_node); // We are certain that it is this type
|
||
|
uint num_faces = p_bsp_node->m_leaf.m_num_faces;
|
||
|
FaceIndex *p_dest_buffer = &(s_face_index_buffer[s_num_face_indicies]);
|
||
|
FaceIndex *p_src_buffer = p_bsp_node->m_leaf.mp_face_idx_array;
|
||
|
|
||
|
for (uint i = 0; i < num_faces; i++)
|
||
|
{
|
||
|
//s_face_index_buffer[s_num_face_indicies++] = p_bsp_leaf->mp_face_idx_array[i];
|
||
|
*(p_dest_buffer++) = *(p_src_buffer++);
|
||
|
}
|
||
|
|
||
|
s_num_face_indicies += num_faces;
|
||
|
Dbg_Assert(s_num_face_indicies < MAX_FACE_INDICIES);
|
||
|
} else { // Node
|
||
|
float f_split_point = p_bsp_node->GetFSplitPoint();
|
||
|
|
||
|
if (bbox.GetMin()[axis] < f_split_point)
|
||
|
{
|
||
|
find_faces(p_bsp_node->GetLessBranch(), bbox);
|
||
|
}
|
||
|
|
||
|
if (bbox.GetMax()[axis] >= f_split_point)
|
||
|
{
|
||
|
find_faces(p_bsp_node->GetGreaterBranch(), bbox);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Calculate the normal of a face
|
||
|
// this is rather expensive if doing a lot of processing, so don't call
|
||
|
// this function more than you need to.
|
||
|
const Mth::Vector CCollObjTriData::GetFaceNormal(int face_idx) const
|
||
|
{
|
||
|
Mth::Vector v0 = GetRawVertexPos(GetFaceVertIndex(face_idx,0));
|
||
|
Mth::Vector v1 = GetRawVertexPos(GetFaceVertIndex(face_idx,1));
|
||
|
Mth::Vector v2 = GetRawVertexPos(GetFaceVertIndex(face_idx,2));
|
||
|
|
||
|
// Find normal
|
||
|
Mth::Vector vTmp1(v1 - v0);
|
||
|
Mth::Vector vTmp2(v2 - v0);
|
||
|
Mth::Vector normal = Mth::CrossProduct(vTmp1, vTmp2);
|
||
|
normal.Normalize();
|
||
|
return normal;
|
||
|
}
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
FaceIndex * CCollObjTriData::FindIntersectingFaces(const Mth::CBBox & line_bbox, uint & num_faces)
|
||
|
{
|
||
|
// Make sure we have a tree
|
||
|
if (!mp_bsp_tree)
|
||
|
{
|
||
|
num_faces = m_num_faces;
|
||
|
Dbg_Assert(num_faces < MAX_FACE_INDICIES);
|
||
|
return s_seq_face_index_buffer;
|
||
|
}
|
||
|
|
||
|
// Search tree
|
||
|
s_num_face_indicies = 0;
|
||
|
find_faces(mp_bsp_tree, line_bbox);
|
||
|
|
||
|
num_faces = s_num_face_indicies;
|
||
|
|
||
|
#if 0
|
||
|
// see if there are any duplicates....
|
||
|
int dups = 0;
|
||
|
if (num_faces)
|
||
|
{
|
||
|
for (uint i = 0;i<num_faces-1;i++)
|
||
|
{
|
||
|
FaceIndex x = s_face_index_buffer[i];
|
||
|
for (uint j = i+1; j<num_faces;j++)
|
||
|
{
|
||
|
if (s_face_index_buffer[j] == x)
|
||
|
{
|
||
|
dups++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printf ("%d/%d/%d\n",dups,num_faces,m_num_faces);
|
||
|
#endif
|
||
|
|
||
|
return s_face_index_buffer;
|
||
|
}
|
||
|
|
||
|
//************************************************************************************
|
||
|
//
|
||
|
// End of BSP code
|
||
|
//
|
||
|
//************************************************************************************
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
CCollObjTriData * CCollObjTriData::Clone(bool instance, bool skip_no_verts)
|
||
|
{
|
||
|
// Don't clone when there is no geometry and skip_no_verts is set
|
||
|
if (skip_no_verts && (m_num_verts == 0))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int intensity_array_size;
|
||
|
CCollObjTriData *m_new_coll = new CCollObjTriData(*this);
|
||
|
|
||
|
Dbg_MsgAssert(!instance, ("CCollObjTriData::Clone() with instances not implemented yet"));
|
||
|
Dbg_MsgAssert(m_num_verts, ("CCollObjTriData::Clone() with no geometry not implemented yet"));
|
||
|
Dbg_Assert(m_num_faces);
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
// m_new_coll->mp_vert_pos = (NsVector*)new char[CCollObjTriData::GetVertElemSize()*m_num_verts];
|
||
|
m_new_coll->mp_raw_vert_pos = mp_raw_vert_pos;
|
||
|
intensity_array_size = m_num_faces * 3;
|
||
|
#else
|
||
|
if (m_use_fixed_verts)
|
||
|
{
|
||
|
m_new_coll->mp_fixed_vert = new SFixedVert[m_num_verts];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
m_new_coll->mp_float_vert = new SFloatVert[m_num_verts];
|
||
|
#else
|
||
|
m_new_coll->mp_vert_pos = new Mth::Vector[m_num_verts];
|
||
|
#endif
|
||
|
}
|
||
|
intensity_array_size = m_num_verts;
|
||
|
#endif // __PLAT_NGC__
|
||
|
if (m_use_face_small)
|
||
|
{
|
||
|
m_new_coll->mp_face_small = new SFaceSmall[m_num_faces];
|
||
|
} else {
|
||
|
m_new_coll->mp_faces = new SFace[m_num_faces];
|
||
|
}
|
||
|
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
if (m_new_coll->mp_float_vert && m_new_coll->mp_faces)
|
||
|
#else
|
||
|
if (m_new_coll->mp_raw_vert_pos && m_new_coll->mp_faces)
|
||
|
#endif
|
||
|
{
|
||
|
#ifdef __PLAT_NGC__
|
||
|
memcpy(m_new_coll->mp_faces, mp_faces , m_num_faces * sizeof(SFace));
|
||
|
#else
|
||
|
if (m_use_fixed_verts)
|
||
|
{
|
||
|
memcpy(m_new_coll->mp_fixed_vert, mp_fixed_vert , m_num_verts * CCollObjTriData::GetVertSmallElemSize());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
memcpy(m_new_coll->mp_float_vert, mp_float_vert , m_num_verts * CCollObjTriData::GetVertElemSize());
|
||
|
#else
|
||
|
memcpy(m_new_coll->mp_vert_pos, mp_vert_pos , m_num_verts * CCollObjTriData::GetVertElemSize());
|
||
|
#endif
|
||
|
}
|
||
|
if (m_use_face_small)
|
||
|
{
|
||
|
memcpy(m_new_coll->mp_face_small, mp_face_small , m_num_faces * sizeof(SFaceSmall));
|
||
|
} else {
|
||
|
memcpy(m_new_coll->mp_faces, mp_faces , m_num_faces * sizeof(SFace));
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
} else {
|
||
|
Dbg_Error("Can't allocate new collision data");
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Copy intensity array if there is one
|
||
|
if (mp_intensity)
|
||
|
{
|
||
|
m_new_coll->mp_intensity = new uint8[intensity_array_size];
|
||
|
memcpy(m_new_coll->mp_intensity, mp_intensity , intensity_array_size * sizeof(uint8));
|
||
|
}
|
||
|
|
||
|
// Set BSP tree to NULL for now until we come up with a method to copy and translate
|
||
|
#ifdef USE_BSP_CLONE
|
||
|
m_new_coll->mp_bsp_tree = mp_bsp_tree->clone(instance);
|
||
|
#else
|
||
|
m_new_coll->mp_bsp_tree = NULL;
|
||
|
#endif // USE_BSP_CLONE
|
||
|
|
||
|
return m_new_coll;
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::Translate(const Mth::Vector & delta_pos)
|
||
|
{
|
||
|
Mth::Vector min_point, max_point;
|
||
|
int i;
|
||
|
|
||
|
|
||
|
// Translate BSP tree
|
||
|
if (mp_bsp_tree)
|
||
|
{
|
||
|
//printf ("WARNING: moving colision geometry that contains a BSP tree. *** CLEARING ***\n");
|
||
|
//mp_bsp_tree = NULL;
|
||
|
mp_bsp_tree->translate(delta_pos);
|
||
|
}
|
||
|
|
||
|
#ifdef __PLAT_NGC__
|
||
|
// Get Verts
|
||
|
Mth::Vector *p_float_verts = NULL;
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
|
||
|
p_float_verts = new Mth::Vector[m_num_verts];
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
get_float_array_from_data(p_float_verts);
|
||
|
|
||
|
// Translate
|
||
|
for ( i = 0; i < m_num_verts; i++ )
|
||
|
{
|
||
|
p_float_verts[i] += delta_pos;
|
||
|
}
|
||
|
|
||
|
// Put Verts
|
||
|
put_float_array_into_data(p_float_verts);
|
||
|
delete [] p_float_verts;
|
||
|
|
||
|
|
||
|
// if ( !mp_offset ) mp_offset = new Mth::Vector;
|
||
|
// mp_offset[0][X] += delta_pos[X];
|
||
|
// mp_offset[0][Y] += delta_pos[Y];
|
||
|
// mp_offset[0][Z] += delta_pos[Z];
|
||
|
#else
|
||
|
// Pos (don't touch W since the color is there)
|
||
|
if (!m_use_fixed_verts)
|
||
|
{
|
||
|
for (i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
mp_float_vert[i].m_pos[X] += delta_pos[X];
|
||
|
mp_float_vert[i].m_pos[Y] += delta_pos[Y];
|
||
|
mp_float_vert[i].m_pos[Z] += delta_pos[Z];
|
||
|
#else
|
||
|
mp_vert_pos[i][X] += delta_pos[X];
|
||
|
mp_vert_pos[i][Y] += delta_pos[Y];
|
||
|
mp_vert_pos[i][Z] += delta_pos[Z];
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
}
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
|
||
|
// BBox
|
||
|
min_point = m_bbox.GetMin() + delta_pos;
|
||
|
max_point = m_bbox.GetMax() + delta_pos;
|
||
|
m_bbox.Set(min_point, max_point);
|
||
|
|
||
|
//Dbg_Message("Min BBox (%f, %f, %f)", m_bbox.GetMin()[X], m_bbox.GetMin()[Y], m_bbox.GetMin()[Z]);
|
||
|
//Dbg_Message("Max BBox (%f, %f, %f)", m_bbox.GetMax()[X], m_bbox.GetMax()[Y], m_bbox.GetMax()[Z]);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::RotateY(const Mth::Vector & world_origin, Mth::ERot90 rot_y)
|
||
|
{
|
||
|
Mth::Vector min_point, max_point;
|
||
|
int i;
|
||
|
|
||
|
// Put object at origin
|
||
|
Translate(-world_origin);
|
||
|
|
||
|
// Rotate BSP tree
|
||
|
if (mp_bsp_tree)
|
||
|
{
|
||
|
mp_bsp_tree->rotate_y(world_origin, rot_y, false); // Don't allow it to do another translation
|
||
|
}
|
||
|
|
||
|
// Convert to floating point, if fixed point data
|
||
|
Mth::Vector *p_float_verts = NULL;
|
||
|
#ifndef __PLAT_NGC__
|
||
|
if (m_use_fixed_verts)
|
||
|
#endif // __PLAT_NGC__
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
|
||
|
p_float_verts = new Mth::Vector[m_num_verts];
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
get_float_array_from_data(p_float_verts);
|
||
|
}
|
||
|
|
||
|
// Rotate
|
||
|
for (i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
|
||
|
if (p_float_verts)
|
||
|
{
|
||
|
p_float_verts[i].RotateY90(rot_y);
|
||
|
}
|
||
|
#ifndef __PLAT_NGC__
|
||
|
else
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
Mth::Vector pos(Mth::Vector::NO_INIT);
|
||
|
GetRawVertexPos(i, pos);
|
||
|
pos.RotateY90(rot_y);
|
||
|
mp_float_vert[i].m_pos[X] = pos[X];
|
||
|
mp_float_vert[i].m_pos[Y] = pos[Y];
|
||
|
mp_float_vert[i].m_pos[Z] = pos[Z];
|
||
|
#else
|
||
|
mp_vert_pos[i].RotateY90(rot_y);
|
||
|
#endif
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
// BBox rotate
|
||
|
min_point = m_bbox.GetMin();
|
||
|
max_point = m_bbox.GetMax();
|
||
|
min_point.RotateY90(rot_y);
|
||
|
max_point.RotateY90(rot_y);
|
||
|
m_bbox.Reset();
|
||
|
m_bbox.AddPoint(min_point);
|
||
|
m_bbox.AddPoint(max_point);
|
||
|
|
||
|
// Convert back to fixed point, if necessary
|
||
|
if (p_float_verts)
|
||
|
{
|
||
|
put_float_array_into_data(p_float_verts);
|
||
|
delete [] p_float_verts;
|
||
|
}
|
||
|
|
||
|
// Put object back
|
||
|
Translate(world_origin);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::Scale(const Mth::Vector & world_origin, const Mth::Vector & scale)
|
||
|
{
|
||
|
// Put object at origin
|
||
|
Translate(-world_origin);
|
||
|
|
||
|
// Scale BSP tree
|
||
|
if (mp_bsp_tree)
|
||
|
{
|
||
|
mp_bsp_tree->scale(world_origin, scale, false); // Don't allow it to do another translation
|
||
|
}
|
||
|
|
||
|
// Convert to floating point, if fixed point data
|
||
|
Mth::Vector *p_float_verts = NULL;
|
||
|
#ifndef __PLAT_NGC__
|
||
|
if (m_use_fixed_verts)
|
||
|
#endif // __PLAT_NGC__
|
||
|
{
|
||
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().TopDownHeap());
|
||
|
p_float_verts = new Mth::Vector[m_num_verts];
|
||
|
Mem::Manager::sHandle().PopContext();
|
||
|
|
||
|
get_float_array_from_data(p_float_verts);
|
||
|
}
|
||
|
|
||
|
// Pos (don't touch W since the color is there)
|
||
|
for (int i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
if (p_float_verts)
|
||
|
{
|
||
|
p_float_verts[i][X] *= scale[X];
|
||
|
p_float_verts[i][Y] *= scale[Y];
|
||
|
p_float_verts[i][Z] *= scale[Z];
|
||
|
}
|
||
|
#ifndef __PLAT_NGC__
|
||
|
else
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
mp_float_vert[i].m_pos[X] *= scale[X];
|
||
|
mp_float_vert[i].m_pos[Y] *= scale[Y];
|
||
|
mp_float_vert[i].m_pos[Z] *= scale[Z];
|
||
|
#else
|
||
|
mp_vert_pos[i][X] *= scale[X];
|
||
|
mp_vert_pos[i][Y] *= scale[Y];
|
||
|
mp_vert_pos[i][Z] *= scale[Z];
|
||
|
#endif
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
// BBox
|
||
|
Mth::Vector min_point(m_bbox.GetMin()), max_point(m_bbox.GetMax());
|
||
|
|
||
|
min_point[X] *= scale[X];
|
||
|
min_point[Y] *= scale[Y];
|
||
|
min_point[Z] *= scale[Z];
|
||
|
|
||
|
max_point[X] *= scale[X];
|
||
|
max_point[Y] *= scale[Y];
|
||
|
max_point[Z] *= scale[Z];
|
||
|
|
||
|
m_bbox.Set(min_point, max_point);
|
||
|
|
||
|
// Convert back to fixed point, if necessary
|
||
|
if (p_float_verts)
|
||
|
{
|
||
|
put_float_array_into_data(p_float_verts);
|
||
|
delete [] p_float_verts;
|
||
|
}
|
||
|
|
||
|
// Put object back
|
||
|
Translate(world_origin);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::SetRawVertexPos(int vert_idx, const Mth::Vector & pos)
|
||
|
{
|
||
|
Dbg_MsgAssert(mp_bsp_tree == NULL, ("Cannot change a vertex within a BSP Tree"));
|
||
|
|
||
|
set_vertex_pos(vert_idx, pos);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::set_vertex_pos(int vert_idx, const Mth::Vector & pos)
|
||
|
{
|
||
|
#ifndef __PLAT_NGC__ // Since they are shared with the render data
|
||
|
if (m_use_fixed_verts)
|
||
|
{
|
||
|
Mth::Vector rel_pos(pos - m_bbox.GetMin());
|
||
|
|
||
|
Dbg_MsgAssert((rel_pos[X] >= 0.0f) && (rel_pos[Y] >= 0.0f) && (rel_pos[Z] >= 0.0f), ("Adding a vert that is outside of bounding box"));
|
||
|
|
||
|
mp_fixed_vert[vert_idx].m_pos[X] = (uint16) (rel_pos[X] * COLLISION_SUB_INCH_PRECISION);
|
||
|
mp_fixed_vert[vert_idx].m_pos[Y] = (uint16) (rel_pos[Y] * COLLISION_SUB_INCH_PRECISION);
|
||
|
mp_fixed_vert[vert_idx].m_pos[Z] = (uint16) (rel_pos[Z] * COLLISION_SUB_INCH_PRECISION);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
mp_float_vert[vert_idx].m_pos[X] = pos[X];
|
||
|
mp_float_vert[vert_idx].m_pos[Y] = pos[Y];
|
||
|
mp_float_vert[vert_idx].m_pos[Z] = pos[Z];
|
||
|
#else
|
||
|
mp_vert_pos[vert_idx][X] = pos[X];
|
||
|
mp_vert_pos[vert_idx][Y] = pos[Y];
|
||
|
mp_vert_pos[vert_idx][Z] = pos[Z];
|
||
|
#endif
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::GetRawVertices(Mth::Vector *p_vert_array) const
|
||
|
{
|
||
|
get_float_array_from_data(p_vert_array);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::SetRawVertices(const Mth::Vector *p_vert_array)
|
||
|
{
|
||
|
// Must set the bounding box first in case data is in fixed point
|
||
|
m_bbox.Reset();
|
||
|
for (int i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
m_bbox.AddPoint(p_vert_array[i]);
|
||
|
}
|
||
|
|
||
|
put_float_array_into_data(p_vert_array);
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
#define MAX_USED 80000
|
||
|
|
||
|
void CCollObjTriData::get_float_array_from_data(Mth::Vector *p_float_array) const
|
||
|
{
|
||
|
#ifdef __PLAT_NGC__
|
||
|
if ( mp_cloned_vert_pos )
|
||
|
{
|
||
|
// Already cloned, just copy.
|
||
|
for ( int i = 0; i < m_num_verts; i++ )
|
||
|
{
|
||
|
p_float_array[i][X] = mp_cloned_vert_pos[i].x;
|
||
|
p_float_array[i][Y] = mp_cloned_vert_pos[i].y;
|
||
|
p_float_array[i][Z] = mp_cloned_vert_pos[i].z;
|
||
|
p_float_array[i][W] = 0.0f;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// We need to pull the verts out of the main render vert list.
|
||
|
int lp;
|
||
|
int lp2;
|
||
|
int index;
|
||
|
unsigned char used[(MAX_USED/8)];
|
||
|
|
||
|
// Build a bit list of used verts.
|
||
|
for ( lp = 0; lp < (MAX_USED/8); lp++ ) used[lp] = 0;
|
||
|
|
||
|
for ( lp = 0; lp < m_num_faces; lp++ )
|
||
|
{
|
||
|
index = mp_faces[lp].m_vertex_index[0];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
index = mp_faces[lp].m_vertex_index[1];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
index = mp_faces[lp].m_vertex_index[2];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
}
|
||
|
|
||
|
// Copy verts out in order.
|
||
|
int num_copied = 0;
|
||
|
for ( lp = 0; lp < (MAX_USED/8); lp++ )
|
||
|
{
|
||
|
if ( used[lp] )
|
||
|
{
|
||
|
for ( lp2 = 0; lp2 < 8; lp2++ )
|
||
|
{
|
||
|
if ( used[lp] & (1<<lp2) )
|
||
|
{
|
||
|
index = (lp<<3) + lp2;
|
||
|
p_float_array[num_copied] = GetRawVertexPos(index);
|
||
|
num_copied++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
for (int i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
p_float_array[i] = GetRawVertexPos(i);
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::put_float_array_into_data(const Mth::Vector *p_float_array)
|
||
|
{
|
||
|
#ifdef __PLAT_NGC__
|
||
|
// Need to change mp_mod to a modified collision vert pointer and alloc new space here.
|
||
|
// the header getpos functions need to check that & pull from there if necessary.
|
||
|
// Also need to remap the face array when we do this.
|
||
|
// Ugh.
|
||
|
|
||
|
|
||
|
|
||
|
if ( mp_cloned_vert_pos )
|
||
|
{
|
||
|
// Already cloned, just copy.
|
||
|
for ( int i = 0; i < m_num_verts; i++ )
|
||
|
{
|
||
|
mp_cloned_vert_pos[i].x = p_float_array[i][X];
|
||
|
mp_cloned_vert_pos[i].y = p_float_array[i][Y];
|
||
|
mp_cloned_vert_pos[i].z = p_float_array[i][Z];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Allocate space for verts & copy over.
|
||
|
mp_cloned_vert_pos = (NsVector*)new float[m_num_verts*3];
|
||
|
|
||
|
for ( int i = 0; i < m_num_verts; i++ )
|
||
|
{
|
||
|
mp_cloned_vert_pos[i].x = p_float_array[i][X];
|
||
|
mp_cloned_vert_pos[i].y = p_float_array[i][Y];
|
||
|
mp_cloned_vert_pos[i].z = p_float_array[i][Z];
|
||
|
}
|
||
|
|
||
|
// Need to remap existing face map.
|
||
|
int lp;
|
||
|
int lp2;
|
||
|
int index;
|
||
|
unsigned char used[(MAX_USED/8)];
|
||
|
|
||
|
// Build a bit list of used verts.
|
||
|
for ( lp = 0; lp < (MAX_USED/8); lp++ ) used[lp] = 0;
|
||
|
|
||
|
for ( lp = 0; lp < m_num_faces; lp++ )
|
||
|
{
|
||
|
index = mp_faces[lp].m_vertex_index[0];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
index = mp_faces[lp].m_vertex_index[1];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
index = mp_faces[lp].m_vertex_index[2];
|
||
|
used[(index>>3)] |= (1<<(index&7));
|
||
|
}
|
||
|
|
||
|
// Remap faces.
|
||
|
int num_copied = 0;
|
||
|
for ( lp = 0; lp < (MAX_USED/8); lp++ )
|
||
|
{
|
||
|
if ( used[lp] )
|
||
|
{
|
||
|
for ( lp2 = 0; lp2 < 8; lp2++ )
|
||
|
{
|
||
|
if ( used[lp] & (1<<lp2) )
|
||
|
{
|
||
|
index = (lp<<3) + lp2;
|
||
|
|
||
|
// See if any face indices match this one & remap if so.
|
||
|
for ( int f = 0; f < m_num_faces; f++ )
|
||
|
{
|
||
|
for ( int v = 0; v < 3; v++ )
|
||
|
{
|
||
|
if ( mp_faces[f].m_vertex_index[v] == index )
|
||
|
{
|
||
|
mp_faces[f].m_vertex_index[v] = num_copied;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
num_copied++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
for (int i = 0; i < m_num_verts; i++)
|
||
|
{
|
||
|
set_vertex_pos(i, p_float_array[i]);
|
||
|
}
|
||
|
#endif // __PLAT_NGC__
|
||
|
}
|
||
|
|
||
|
// This is called once when a scene is first loaded, from ScriptParseNodeArray
|
||
|
// and only if the OCCLUDER flag is set in the object's node
|
||
|
// here we loop over the polgons in the object
|
||
|
// and create a single occluder polygon
|
||
|
// which is added to the world
|
||
|
//
|
||
|
// (these will need to be deleted when the scene is unloaded)
|
||
|
void CCollObjTriData::ProcessOcclusion( void )
|
||
|
{
|
||
|
// Scan through and find pairs of triangles that share 2 verts - i.e. that form quads.
|
||
|
for( int fidx0 = 0; fidx0 < m_num_faces - 1; ++fidx0 )
|
||
|
{
|
||
|
SFaceInfo *p_face0 = get_face_info(fidx0);
|
||
|
|
||
|
// Check we haven't already used this face.
|
||
|
if( p_face0->m_flags & ( 1 << 31 ))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
Mth::Vector v[4];
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex(fidx0, 0));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex(fidx0, 1));
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex(fidx0, 2));
|
||
|
// printf( "Occlusion Triangle %d\n(%f,%f,%f)\n(%f,%f,%f)\n(%f,%f,%f)\n",fidx0,v[0][X],v[0][Y],v[0][Z],v[1][X],v[1][Y],v[1][Z],v[2][X],v[2][Y],v[2][Z] );
|
||
|
|
||
|
for( int fidx1 = fidx0 + 1; fidx1 < m_num_faces; ++fidx1 )
|
||
|
{
|
||
|
SFaceInfo *p_face1 = get_face_info(fidx1);
|
||
|
|
||
|
// Check we haven't already used this face.
|
||
|
if( p_face1->m_flags & ( 1 << 31 ))
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex(fidx1, 0));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex(fidx1, 1));
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex(fidx1, 2));
|
||
|
// printf( "Occlusion Triangle %d\n(%f,%f,%f)\n(%f,%f,%f)\n(%f,%f,%f)\n",fidx1,v[0][X],v[0][Y],v[0][Z],v[1][X],v[1][Y],v[1][Z],v[2][X],v[2][Y],v[2][Z] );
|
||
|
|
||
|
int indices_matched0[3] = { -1, -1, -1 };
|
||
|
int indices_matched1[3] = { -1, -1, -1 };
|
||
|
int num_indices_matched = 0;
|
||
|
|
||
|
for( int i = 0; i < 3; ++i )
|
||
|
{
|
||
|
if( GetFaceVertIndex(fidx0, i) == GetFaceVertIndex(fidx1, 0) )
|
||
|
{
|
||
|
indices_matched0[i] = GetFaceVertIndex(fidx0, i);
|
||
|
indices_matched1[0] = GetFaceVertIndex(fidx1, 0);
|
||
|
++num_indices_matched;
|
||
|
}
|
||
|
else if( GetFaceVertIndex(fidx0, i) == GetFaceVertIndex(fidx1, 1) )
|
||
|
{
|
||
|
indices_matched0[i] = GetFaceVertIndex(fidx0, i);
|
||
|
indices_matched1[1] = GetFaceVertIndex(fidx1, 1);
|
||
|
++num_indices_matched;
|
||
|
}
|
||
|
else if( GetFaceVertIndex(fidx0, i) == GetFaceVertIndex(fidx1, 2) )
|
||
|
{
|
||
|
indices_matched0[i] = GetFaceVertIndex(fidx0, i);
|
||
|
indices_matched1[2] = GetFaceVertIndex(fidx1, 2);
|
||
|
++num_indices_matched;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Three indices matched is just plain wrong.
|
||
|
Dbg_Assert( num_indices_matched < 3 );
|
||
|
|
||
|
// Two indices matched is just what we want.
|
||
|
if( num_indices_matched == 2 )
|
||
|
{
|
||
|
// Make sure that the 2 tris lie in the same plane, which is no longer necessarily the case since they could be
|
||
|
// tris which adjoin at a right angle.
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex( fidx0, 0 ));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex( fidx0, 1 ));
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex( fidx0, 2 ));
|
||
|
Mth::Vector norm0 = Mth::CrossProduct( v[1] - v[0], v[2] - v[0] );
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex( fidx1, 0 ));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex( fidx1, 1 ));
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex( fidx1, 2 ));
|
||
|
Mth::Vector norm1 = Mth::CrossProduct( v[1] - v[0], v[2] - v[0] );
|
||
|
norm0.Normalize();
|
||
|
norm1.Normalize();
|
||
|
|
||
|
if(( fabs( norm1[X]-norm0[X]) <= 0.05f ) && ( fabs( norm1[Y]-norm0[Y]) <= 0.05f ) && ( fabs( norm1[Z]-norm0[Z]) <= 0.05f ))
|
||
|
{
|
||
|
|
||
|
// These two tris are coplanar.
|
||
|
|
||
|
// Get the index from tri1 that isn't shared with tri0.
|
||
|
int unshared_tri1_index = -1;
|
||
|
for( int i = 0; i < 3; ++i )
|
||
|
{
|
||
|
if( indices_matched1[i] == -1 )
|
||
|
{
|
||
|
unshared_tri1_index = GetFaceVertIndex(fidx1, i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
Dbg_Assert( unshared_tri1_index >= 0 );
|
||
|
|
||
|
// Fill in the missing 2 verts, one from each tri. What is important here is which side of triangle0 that
|
||
|
// that triangle1 shares, since this will determine the overall order of the quad abcd.
|
||
|
if(( indices_matched0[0] >= 0 ) && ( indices_matched0[1] >= 0 ))
|
||
|
{
|
||
|
// They share side 0->1. Thus the quad will be t0(0), t1(unshared), t0(1), t0(2).
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex(fidx0, 0));
|
||
|
v[1] = GetRawVertexPos(unshared_tri1_index);
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex(fidx0, 1));
|
||
|
v[3] = GetRawVertexPos(GetFaceVertIndex(fidx0, 2));
|
||
|
}
|
||
|
else if(( indices_matched0[1] >= 0 ) && ( indices_matched0[2] >= 0 ))
|
||
|
{
|
||
|
// They share side 1->2. Thus the quad will be t0(0), t0(1), t1(unshared), t0(2).
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex(fidx0, 0));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex(fidx0, 1));
|
||
|
v[2] = GetRawVertexPos(unshared_tri1_index);
|
||
|
v[3] = GetRawVertexPos(GetFaceVertIndex(fidx0, 2));
|
||
|
}
|
||
|
else if(( indices_matched0[0] >= 0 ) && ( indices_matched0[2] >= 0 ))
|
||
|
{
|
||
|
// They share side 2->0. Thus the quad will be t0(0), t0(1), t0(2), t1(unshared).
|
||
|
v[0] = GetRawVertexPos(GetFaceVertIndex(fidx0, 0));
|
||
|
v[1] = GetRawVertexPos(GetFaceVertIndex(fidx0, 1));
|
||
|
v[2] = GetRawVertexPos(GetFaceVertIndex(fidx0, 2));
|
||
|
v[3] = GetRawVertexPos(unshared_tri1_index);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
}
|
||
|
|
||
|
// printf( "Occlusion Quad\n(%f,%f,%f)\n(%f,%f,%f)\n(%f,%f,%f)\n(%f,%f,%f)\n",v[0][X],v[0][Y],v[0][Z],v[1][X],v[1][Y],v[1][Z],v[2][X],v[2][Y],v[2][Z],v[3][X],v[3][Y],v[3][Z] );
|
||
|
|
||
|
// Register this quad with the engine.
|
||
|
Nx::CEngine::sAddOcclusionPoly( 4, v, m_checksum );
|
||
|
|
||
|
// Flag the two tris as having been used.
|
||
|
Dbg_Assert(( p_face0->m_flags & ( 1 << 31 )) == 0 );
|
||
|
Dbg_Assert(( p_face1->m_flags & ( 1 << 31 )) == 0 );
|
||
|
p_face0->m_flags |= ( 1 << 31 );
|
||
|
p_face1->m_flags |= ( 1 << 31 );
|
||
|
|
||
|
// Break out of this inner loop now since we have found a pair.
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Scan through and clear 'used' flag on faces.
|
||
|
for( int fidx0 = 0; fidx0 < m_num_faces; ++fidx0 )
|
||
|
{
|
||
|
SFaceInfo *p_face0 = get_face_info(fidx0);
|
||
|
p_face0->m_flags &= ~( 1 << 31 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
#ifdef __DEBUG_CODE__
|
||
|
|
||
|
void CCollObjTriData::DebugRender(uint32 ignore_1, uint32 ignore_0)
|
||
|
{
|
||
|
#ifdef __NOPT_ASSERT__
|
||
|
static Mth::Matrix ident_matrix(0.0f, 0.0f, 0.0f); // static so it doesn't waste time in the constuctor
|
||
|
|
||
|
// simple culling based on the world bbox
|
||
|
Mth::Vector mid = (GetBBox().GetMax() + GetBBox().GetMin())/2.0f;
|
||
|
float radius = (mid - GetBBox().GetMin()).Length();
|
||
|
|
||
|
if (Nx::CEngine::GetWireframeMode() == 6) // 6 = occlusion
|
||
|
{
|
||
|
// Rendering as 2d, to demontrate occlusion
|
||
|
// we try to get the visibility flag from the engine
|
||
|
|
||
|
#if 0 //def __PLAT_NGPS__
|
||
|
bool drawn = true;
|
||
|
|
||
|
Nx::CPs2Sector* p_sector = (Nx::CPs2Sector*)Nx::CEngine::sGetSector(m_checksum);
|
||
|
if (p_sector)
|
||
|
{
|
||
|
|
||
|
NxPs2::CGeomNode *p_node = (p_sector->GetEngineObject());
|
||
|
if (p_node)
|
||
|
{
|
||
|
drawn = p_node->WasRendered();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
if (drawn)
|
||
|
#else
|
||
|
if ( Nx::CEngine::sIsVisible(mid,radius))
|
||
|
#endif
|
||
|
{
|
||
|
Nx::CSector* p_sector = Nx::CEngine::sGetSector(m_checksum); // SLOWWWWWWWWWWWWW
|
||
|
if (p_sector && !p_sector->GetVisibility())
|
||
|
{
|
||
|
DebugRender2D(ignore_1, ignore_0,0x000080); // red = hidden
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DebugRender2D(ignore_1, ignore_0,0x808080); // grey = visible
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
// Mick: Should be abel to use the actual Occluded bits here....
|
||
|
if (NxPs2::IsInFrame( mid, radius ) && NxPs2::TestSphereAgainstOccluders(&mid,radius,0))
|
||
|
DebugRender2D(ignore_1, ignore_0,0x40c040); // green = occluded
|
||
|
else
|
||
|
#endif
|
||
|
{
|
||
|
DebugRender2DBBox(ignore_1, ignore_0,0x003030); // dk yellow box and
|
||
|
DebugRender2DOct(ignore_1, ignore_0,0x003000); // dark green ocotogon off camera
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if ( Nx::CEngine::sIsVisible(mid,radius))
|
||
|
# ifdef __PLAT_NGPS__
|
||
|
if (NxPs2::IsInFrame( mid, radius ))
|
||
|
DebugRender(ident_matrix, ignore_1, ignore_0, false);
|
||
|
# endif
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::DebugRender(const Mth::Matrix & transform, uint32 ignore_1, uint32 ignore_0, bool do_transform)
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
|
||
|
uint32 rgb = 0x000000;
|
||
|
int n = m_num_faces;
|
||
|
int r=0;
|
||
|
int g=0;
|
||
|
int b=0;
|
||
|
|
||
|
NxPs2::DMAOverflowOK = 2;
|
||
|
|
||
|
|
||
|
switch (Nx::CEngine::GetWireframeMode())
|
||
|
{
|
||
|
case 1: // Polygon density, red = high, white=higher
|
||
|
{
|
||
|
#define peak 500
|
||
|
if (n <= peak )
|
||
|
{
|
||
|
r = (255 * (n)) / peak; // r ramps up (black to red)
|
||
|
}
|
||
|
else if (n <= peak * 2)
|
||
|
{
|
||
|
r = 255;
|
||
|
b = (255 * (n - peak) / (peak)); // b&g ramps up (to white)
|
||
|
g = b;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
r = g = b = 255;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case 2: // Low Polygon density, red = high, white=higher
|
||
|
{
|
||
|
#define peak 500
|
||
|
if (n <= 2 )
|
||
|
{
|
||
|
r = g = b = 255; // White = two or less
|
||
|
}
|
||
|
else if (n <= 4)
|
||
|
{
|
||
|
g = 255; // Green = 4 or less
|
||
|
|
||
|
}
|
||
|
else if (n <= 8)
|
||
|
{
|
||
|
b = 255; // blue = 8 or less
|
||
|
}
|
||
|
else if (n <= 16)
|
||
|
{
|
||
|
r = b = 255; // Magenta = 16 or less
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case 3: // Each object a different color, based on checksum
|
||
|
{
|
||
|
r = (m_checksum >>16) & 0xff;
|
||
|
g = (m_checksum >>8) & 0xff;
|
||
|
b = (m_checksum ) & 0xff;
|
||
|
}
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
// fix up anything I did stupid
|
||
|
if (r<0) r=0;
|
||
|
if (r>255) r=255;
|
||
|
if (g<0) g=0;
|
||
|
if (g>255) g=255;
|
||
|
if (b<0) b=0;
|
||
|
if (b>255) b=255;
|
||
|
|
||
|
rgb = (b<<16)|(g<<8)|r;
|
||
|
|
||
|
uint32 current = 12345678;
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
// scan through all verts, and see if any are close, but not close enough....
|
||
|
// obviously this will be somewhat slow
|
||
|
NxPs2::BeginLines3D(0x80000000 + (0x00ff00ff)); // Magenta = unwelded verts
|
||
|
|
||
|
for (int i=0;i<m_num_verts-1;i++)
|
||
|
{
|
||
|
for (int j = i+1; j<m_num_verts;j++)
|
||
|
{
|
||
|
float len = (mp_vert_pos[i]-mp_vert_pos[j]).LengthSqr();
|
||
|
if ( len >0.0000001f && len < 1.0f)
|
||
|
{
|
||
|
|
||
|
Mth::Vector *v0,*v1;
|
||
|
v0 = &mp_vert_pos[i];
|
||
|
v1 = &mp_vert_pos[j];
|
||
|
NxPs2::DrawLine3D((*v0)[X],(*v0)[Y],(*v0)[Z],(*v0)[X],(*v0)[Y]+100.0f,(*v0)[Z]);
|
||
|
NxPs2::DrawLine3D((*v1)[X],(*v1)[Y],(*v1)[Z],(*v1)[X],(*v1)[Y]+100.0f,(*v1)[Z]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
NxPs2::EndLines3D();
|
||
|
return;
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
Mth::Vector v0, v1, v2;
|
||
|
|
||
|
|
||
|
for (int fidx = 0; fidx < m_num_faces; fidx++)
|
||
|
{
|
||
|
SFaceInfo *face = get_face_info(fidx);
|
||
|
|
||
|
if (!(face->m_flags & ignore_1) && !(~face->m_flags & ignore_0))
|
||
|
{
|
||
|
|
||
|
if (Nx::CEngine::GetWireframeMode() == 0) // face flags
|
||
|
{
|
||
|
rgb = 0xffffff; // white = no flags
|
||
|
if (face->m_flags & mFD_VERT)
|
||
|
{
|
||
|
rgb = 0x4040ff; // red = vert
|
||
|
}
|
||
|
if (face->m_flags & mFD_TRIGGER)
|
||
|
{
|
||
|
rgb = 0xff4040; // blue = trigger
|
||
|
}
|
||
|
if (face->m_flags & mFD_WALL_RIDABLE)
|
||
|
{
|
||
|
rgb = 0x00ffff; // yellow = wallride
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// check for context changes
|
||
|
if (current != rgb)
|
||
|
{
|
||
|
if (current == 12345678)
|
||
|
{
|
||
|
NxPs2::BeginLines3D(0x80000000 + (0x00ffffff & rgb));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NxPs2::ChangeLineColor(0x80000000 + (0x00ffffff & rgb));
|
||
|
}
|
||
|
current = rgb;
|
||
|
}
|
||
|
|
||
|
#ifdef FIXED_POINT_VERTICES
|
||
|
if (do_transform)
|
||
|
{
|
||
|
v0 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 0)));
|
||
|
v1 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 1)));
|
||
|
v2 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 2)));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
v0 = GetRawVertexPos(GetFaceVertIndex(fidx, 0));
|
||
|
v1 = GetRawVertexPos(GetFaceVertIndex(fidx, 1));
|
||
|
v2 = GetRawVertexPos(GetFaceVertIndex(fidx, 2));
|
||
|
}
|
||
|
#else
|
||
|
if (do_transform)
|
||
|
{
|
||
|
v0 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 0)]);
|
||
|
v1 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 1)]);
|
||
|
v2 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 2)]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
v0 = mp_vert_pos[GetFaceVertIndex(fidx, 0)];
|
||
|
v1 = mp_vert_pos[GetFaceVertIndex(fidx, 1)];
|
||
|
v2 = mp_vert_pos[GetFaceVertIndex(fidx, 2)];
|
||
|
}
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
|
||
|
NxPs2::DrawLine3D(v0[X], v0[Y], v0[Z], v1[X], v1[Y], v1[Z]);
|
||
|
NxPs2::DrawLine3D(v0[X], v0[Y], v0[Z], v2[X], v2[Y], v2[Z]);
|
||
|
NxPs2::DrawLine3D(v2[X], v2[Y], v2[Z], v1[X], v1[Y], v1[Z]);
|
||
|
}
|
||
|
}
|
||
|
// only if we actually drew some
|
||
|
if ( current != 12345678)
|
||
|
{
|
||
|
NxPs2::EndLines3D();
|
||
|
}
|
||
|
#else
|
||
|
const uint32 rgba = 0x0000FF80;
|
||
|
|
||
|
for (int fidx = 0; fidx < m_num_faces; fidx++)
|
||
|
{
|
||
|
Mth::Vector v0, v1, v2;
|
||
|
|
||
|
if (do_transform)
|
||
|
{
|
||
|
#if defined(FIXED_POINT_VERTICES) || defined(__PLAT_NGC__)
|
||
|
v0 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 0)));
|
||
|
v1 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 1)));
|
||
|
v2 = transform.TransformAsPos(GetRawVertexPos(GetFaceVertIndex(fidx, 2)));
|
||
|
#else
|
||
|
v0 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 0)]);
|
||
|
v1 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 1)]);
|
||
|
v2 = transform.TransformAsPos(mp_vert_pos[GetFaceVertIndex(fidx, 2)]);
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#if defined(FIXED_POINT_VERTICES) || defined(__PLAT_NGC__)
|
||
|
v0 = GetRawVertexPos(GetFaceVertIndex(fidx, 0));
|
||
|
v1 = GetRawVertexPos(GetFaceVertIndex(fidx, 1));
|
||
|
v2 = GetRawVertexPos(GetFaceVertIndex(fidx, 2));
|
||
|
#else
|
||
|
v0 = mp_vert_pos[GetFaceVertIndex(fidx, 0)];
|
||
|
v1 = mp_vert_pos[GetFaceVertIndex(fidx, 1)];
|
||
|
v2 = mp_vert_pos[GetFaceVertIndex(fidx, 2)];
|
||
|
#endif // FIXED_POINT_VERTICES
|
||
|
}
|
||
|
// Draw Triangle
|
||
|
Gfx::AddDebugLine(v0, v1, rgba, rgba, 1);
|
||
|
Gfx::AddDebugLine(v1, v2, rgba, rgba, 1);
|
||
|
Gfx::AddDebugLine(v2, v0, rgba, rgba, 1);
|
||
|
}
|
||
|
#endif // __PLAT_NGPS__
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
static Mth::Vector x;
|
||
|
static Mth::Vector y;
|
||
|
|
||
|
inline void rot(Mth::Vector &v)
|
||
|
{
|
||
|
float vx = v[X];
|
||
|
float vy = v[Z];
|
||
|
v[X] = vx * x[X] + vy * x[Z];
|
||
|
v[Z] = vx * y[X] + vy * y[Z];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
static float debug_2d_scale = 0.02f;
|
||
|
static Mth::Vector s_overhead_cam_pos;
|
||
|
|
||
|
void _debug_change_2d_scale(float x)
|
||
|
{
|
||
|
debug_2d_scale *= x;
|
||
|
if (debug_2d_scale > 0.5f) debug_2d_scale = 0.5f;
|
||
|
if (debug_2d_scale < 0.002f) debug_2d_scale = 0.002f;
|
||
|
|
||
|
}
|
||
|
|
||
|
void OverheadLine(Mth::Vector v0, Mth::Vector v1)
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
|
||
|
Mth::Vector offset;
|
||
|
offset.Set(320.0f,0.0f,224.0f);
|
||
|
|
||
|
v0 -= s_overhead_cam_pos;
|
||
|
v1 -= s_overhead_cam_pos;
|
||
|
|
||
|
v0 *= debug_2d_scale;
|
||
|
v1 *= debug_2d_scale;
|
||
|
|
||
|
rot(v0);
|
||
|
rot(v1);
|
||
|
|
||
|
v0 += offset;
|
||
|
v1 += offset;
|
||
|
|
||
|
if (v0[X] < 0 && v1[X] < 0) return;
|
||
|
if (v0[Z] < 0 && v1[Z] < 0) return;
|
||
|
if (v0[X] > 639 && v1[X] >639) return;
|
||
|
if (v0[Z] > 447 && v1[Z] > 447) return;
|
||
|
|
||
|
|
||
|
// Some simple clipping
|
||
|
|
||
|
NxPs2::DrawLine2D(v0[X], v0[Z], 0.0f, v1[X], v1[Z],0.0f);
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void CCollObjTriData::DebugRender2D(uint32 ignore_1, uint32 ignore_0, uint32 visible)
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
|
||
|
|
||
|
Gfx::Camera *cur_camera = Nx::CViewportManager::sGetCamera( 0 );
|
||
|
s_overhead_cam_pos = cur_camera->GetPos();
|
||
|
|
||
|
// get orientation from the camere
|
||
|
y = cur_camera->GetMatrix()[Z];
|
||
|
y[Y] = 0.0f;
|
||
|
y.Normalize();
|
||
|
x[X] = y[Z];
|
||
|
x[Y] = 0.0f;
|
||
|
x[Z] = - y[X];
|
||
|
|
||
|
uint32 rgb = visible; // blue = visible
|
||
|
Mth::Vector v0, v1, v2;
|
||
|
NxPs2::BeginLines2D(0x80000000 + (0x00ffffff & rgb));
|
||
|
for (int fidx = 0; fidx < m_num_faces; fidx++)
|
||
|
{
|
||
|
SFaceInfo *face = get_face_info(fidx);
|
||
|
if (!(face->m_flags & ignore_1) && !(~face->m_flags & ignore_0))
|
||
|
{
|
||
|
GetRawVertexPos(GetFaceVertIndex(fidx, 0), v0);
|
||
|
GetRawVertexPos(GetFaceVertIndex(fidx, 1), v1);
|
||
|
GetRawVertexPos(GetFaceVertIndex(fidx, 2), v2);
|
||
|
OverheadLine(v0,v1);
|
||
|
OverheadLine(v1,v2);
|
||
|
OverheadLine(v2,v0);
|
||
|
}
|
||
|
}
|
||
|
NxPs2::EndLines2D();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CCollObjTriData::DebugRender2DBBox(uint32 ignore_1, uint32 ignore_0, uint32 visible)
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
|
||
|
|
||
|
Gfx::Camera *cur_camera = Nx::CViewportManager::sGetCamera( 0 );
|
||
|
|
||
|
// get orientation from the camere
|
||
|
y = cur_camera->GetMatrix()[Z];
|
||
|
y[Y] = 0.0f;
|
||
|
y.Normalize();
|
||
|
x[X] = y[Z];
|
||
|
x[Y] = 0.0f;
|
||
|
x[Z] = - y[X];
|
||
|
|
||
|
uint32 rgb = visible; // blue = visible
|
||
|
|
||
|
Mth::Vector v0, v1, v2,v3;
|
||
|
|
||
|
NxPs2::BeginLines2D(0x80000000 + (0x00ffffff & rgb));
|
||
|
v0 = GetBBox().GetMax();
|
||
|
v2 = GetBBox().GetMin();
|
||
|
v1[X] = v2[X];
|
||
|
v1[Z] = v0[Z];
|
||
|
v3[X] = v0[X];
|
||
|
v3[Z] = v2[Z];
|
||
|
|
||
|
OverheadLine(v0,v1);
|
||
|
OverheadLine(v1,v2);
|
||
|
OverheadLine(v2,v3);
|
||
|
OverheadLine(v3,v0);
|
||
|
NxPs2::EndLines2D();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// draw as an octagon, to simultate the bounding sphere
|
||
|
void CCollObjTriData::DebugRender2DOct(uint32 ignore_1, uint32 ignore_0, uint32 visible)
|
||
|
{
|
||
|
#ifdef __PLAT_NGPS__
|
||
|
|
||
|
|
||
|
Gfx::Camera *cur_camera = Nx::CViewportManager::sGetCamera( 0 );
|
||
|
|
||
|
// get orientation from the camere
|
||
|
y = cur_camera->GetMatrix()[Z];
|
||
|
y[Y] = 0.0f;
|
||
|
y.Normalize();
|
||
|
x[X] = y[Z];
|
||
|
x[Y] = 0.0f;
|
||
|
x[Z] = - y[X];
|
||
|
|
||
|
uint32 rgb = visible; // blue = visible
|
||
|
|
||
|
Mth::Vector v[8];
|
||
|
|
||
|
Mth::Vector offset;
|
||
|
|
||
|
offset.Set(320.0f,0.0f,224.0f);
|
||
|
|
||
|
|
||
|
// simple culling based on the world bbox
|
||
|
Mth::Vector mid = (GetBBox().GetMax() + GetBBox().GetMin())/2.0f;
|
||
|
float radius = (mid - GetBBox().GetMin()).Length();
|
||
|
|
||
|
float half = radius * 0.707106f;
|
||
|
|
||
|
|
||
|
v[0].Set(-half,0,-half);
|
||
|
v[2].Set( half,0,-half);
|
||
|
v[4].Set( half,0, half);
|
||
|
v[6].Set(-half,0, half);
|
||
|
v[1].Set( 0 ,0,-radius);
|
||
|
v[3].Set( radius,0, 0 );
|
||
|
v[5].Set( 0 ,0, radius);
|
||
|
v[7].Set(-radius,0, 0 );
|
||
|
|
||
|
NxPs2::BeginLines2D(0x80000000 + (0x00ffffff & rgb));
|
||
|
for (int i=0;i<8;i++)
|
||
|
{
|
||
|
v[i] += mid;
|
||
|
}
|
||
|
for (int i=0;i<8;i++)
|
||
|
{
|
||
|
OverheadLine(v[i], v[(i+1)&7]);
|
||
|
}
|
||
|
NxPs2::EndLines2D();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
// Stub function for
|
||
|
void CCollObjTriData::DebugRender(uint32 ignore_1, uint32 ignore_0) {}
|
||
|
void CCollObjTriData::DebugRender(const Mth::Matrix & transform, uint32 ignore_1, uint32 ignore_0, bool do_transform) {}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// Checks to see if a coll sector has any potential "Uberfrig" holes or seams
|
||
|
// that would be where there is NO ground beneath a point
|
||
|
// Algorithm:
|
||
|
// for each edge or each triangle
|
||
|
// find the midpoint of the edge
|
||
|
// for left and right sides
|
||
|
// check if there is a hole at either of 0.000001, 0.0001, 0.1, 1.0 inches away (perp to edge)
|
||
|
// if hole, then check six feet away
|
||
|
// if collision six feet away, then we classify this as a hole, and flag it in the level
|
||
|
// (flag the edge, and the point with a hole)
|
||
|
//
|
||
|
// Note: the checks encompass the whole world, not just this sector
|
||
|
#ifdef __DEBUG_CODE__
|
||
|
|
||
|
bool CheckEdgeAt(Mth::Vector& mid, Mth::Vector& left, float dist, CFeeler& feeler)
|
||
|
{
|
||
|
|
||
|
float up = 1000.0f;
|
||
|
|
||
|
/*
|
||
|
// if we are next to a wall, then we need to check from a much greater height
|
||
|
feeler.SetLine(mid + left * 10.0f + up, mid - left * 10.0f + up);
|
||
|
if (feeler.GetCollision())
|
||
|
{
|
||
|
up = 1000.0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// need to check for wall from both directions, I think
|
||
|
feeler.FlipDirection();
|
||
|
if (feeler.GetCollision())
|
||
|
{
|
||
|
up = 1000.0f;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
feeler.SetLine(mid + left * dist + Mth::Vector(0.0f,up,0.0f),
|
||
|
mid + left * dist + Mth::Vector(0.0f,-1000.0f,0.0f));
|
||
|
// mid + left * dist + Mth::Vector(0.0f,-5800.0f,0.0f));
|
||
|
|
||
|
// feeler.DebugLine(0,255,0);
|
||
|
|
||
|
return feeler.GetCollision(false);
|
||
|
}
|
||
|
|
||
|
void CheckEdgeForHoles(Mth::Vector v0, Mth::Vector v1)
|
||
|
{
|
||
|
Mth::Vector mid = (v0 + v1) / 2.0f;
|
||
|
Mth::Vector left = v1 - v0;
|
||
|
left.Normalize();
|
||
|
if (left[X] == 0.0f && left[Z] == 0.0f)
|
||
|
{
|
||
|
// edge is perfectly vertical, so return
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// make left vector be at right angles to the edge in the XZ plane
|
||
|
float x = left[X];
|
||
|
left[X] = left[Z];
|
||
|
left[Z] = -x;
|
||
|
left[Y] = 0;
|
||
|
|
||
|
CFeeler feeler;
|
||
|
|
||
|
// first check six feet away, to eliminate around the edge of the level
|
||
|
|
||
|
if (!CheckEdgeAt(mid, left, 72.0f,feeler))
|
||
|
{
|
||
|
// hole six feet away, so return
|
||
|
// Gfx::AddDebugLine(mid+left*60.0f, mid+left*60.0f * 10.0f,0xff0000);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
for (float x = 0.001f; x<0.0015f; x *= 10.0f) // does 0.001, 0.01, 0.10
|
||
|
{
|
||
|
if (!CheckEdgeAt(mid,left,x,feeler))
|
||
|
{
|
||
|
// Found a hole!!!
|
||
|
// we draw bunch of lines of differning length, so we can see it when we zoom in
|
||
|
|
||
|
Gfx::AddDebugLine(v0, v1,0xff00ff); // magenta = bad edge
|
||
|
|
||
|
// feeler.DebugLine(0,0,255); // blue = actual collision line
|
||
|
Gfx::AddDebugLine(mid+left*x, mid+left*x + Mth::Vector(0,40,0),0xffff);
|
||
|
Gfx::AddDebugLine(mid+left*x, mid+left*x + Mth::Vector(0,200,0),0xffff);
|
||
|
Gfx::AddDebugLine(mid+left*x, mid+left*x + Mth::Vector(0,1000,0),0xffff);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
|
||
|
void CCollObjTriData::CheckForHoles()
|
||
|
{
|
||
|
|
||
|
printf ("\nChecking for unvelded verts in object with %d verts\n",m_num_verts);
|
||
|
|
||
|
for (int i=0;i<m_num_verts-1;i++)
|
||
|
{
|
||
|
for (int j = i+1; j<m_num_verts;j++)
|
||
|
{
|
||
|
float len = (GetRawVertexPos(i)-GetRawVertexPos(j)).LengthSqr();
|
||
|
if ( len >0.0000001f && len < 0.1f)
|
||
|
{
|
||
|
|
||
|
#ifndef __PLAT_NGC__
|
||
|
Gfx::AddDebugLine(GetRawVertexPos(i), GetRawVertexPos(i) + Mth::Vector(0,400,0),0xff00ff);
|
||
|
Gfx::AddDebugLine(GetRawVertexPos(i), GetRawVertexPos(i) + Mth::Vector(0,40,0),0xff00ff);
|
||
|
#endif // __PLAT_NGC__
|
||
|
printf ("Found one, at dist %f,m check the magenta lines\n",len);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
printf ("Then Checking for holes in object with %d faces\n",m_num_faces);
|
||
|
for (int fidx = 0; fidx < m_num_faces; fidx++)
|
||
|
{
|
||
|
|
||
|
SFaceInfo *face = get_face_info(fidx);
|
||
|
if (!(face->m_flags & mFD_NON_COLLIDABLE))
|
||
|
{
|
||
|
CheckEdgeForHoles(GetRawVertexPos(GetFaceVertIndex(fidx, 0)),GetRawVertexPos(GetFaceVertIndex(fidx, 1)));
|
||
|
CheckEdgeForHoles(GetRawVertexPos(GetFaceVertIndex(fidx, 1)),GetRawVertexPos(GetFaceVertIndex(fidx, 2)));
|
||
|
CheckEdgeForHoles(GetRawVertexPos(GetFaceVertIndex(fidx, 2)),GetRawVertexPos(GetFaceVertIndex(fidx, 0)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
} // namespace Nx
|
||
|
|