243 lines
7.4 KiB
C++
243 lines
7.4 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
/*
|
|
====================
|
|
idSurface_Traceable::sdTraceableTriangleHash::sdTraceableTriangleHash
|
|
====================
|
|
*/
|
|
idSurface_Traceable::sdTraceableTriangleHash::sdTraceableTriangleHash( idSurface_Traceable& surface, const int binsPerAxis, const int snapFractions ) {
|
|
|
|
this->binsPerAxis = binsPerAxis;
|
|
this->snapFractions = snapFractions;
|
|
bounds = surface.GetBounds();
|
|
|
|
// spread the bounds so it will never have a zero size
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
bounds[0][i] = idMath::Floor( bounds[0][i] - 1 );
|
|
bounds[1][i] = idMath::Ceil( bounds[1][i] + 1 );
|
|
scale[i] = ( bounds[1][i] - bounds[0][i] ) / binsPerAxis;
|
|
|
|
intMins[i] = idMath::Ftoi( bounds[0][i] * snapFractions );
|
|
intScale[i] = idMath::Ftoi( scale[i] * snapFractions );
|
|
if ( intScale[ i ] < 1 ) {
|
|
intScale[ i ] = 1;
|
|
}
|
|
}
|
|
|
|
bins = new hashBin_t[ binsPerAxis * binsPerAxis * binsPerAxis ];
|
|
SIMDProcessor->Memset( bins, 0, binsPerAxis * binsPerAxis * binsPerAxis * sizeof( hashBin_t ) );
|
|
|
|
// insert triangles into bins
|
|
hashTriangle_t* tri;
|
|
idBounds triBounds;
|
|
int triBins[2][3];
|
|
const idDrawVert* verts = surface.GetVertices();
|
|
const vertIndex_t* indexes = surface.GetIndexes();
|
|
|
|
for ( int i = 0; i < surface.GetNumIndexes(); i += 3 ) {
|
|
triBounds.Clear();
|
|
for ( int k = 0; k < 3; k++ ) {
|
|
triBounds.AddPoint( verts[ indexes[ i + k ] ].xyz );
|
|
}
|
|
for ( int k = 0; k < 3; k++ ) {
|
|
triBins[ 0 ][ k ] = idMath::Ftoi( idMath::Floor( ( triBounds[ 0 ][ k ] + .5f / snapFractions ) * snapFractions ) );
|
|
triBins[ 0 ][ k ] = ( triBins[ 0 ][ k ] - intMins[ k ] ) / intScale[ k ];
|
|
if ( triBins[ 0 ][ k ] < 0 ) {
|
|
triBins[ 0 ][ k ] = 0;
|
|
} else if ( triBins[ 0 ][ k ] >= binsPerAxis ) {
|
|
triBins[ 0 ][ k ] = binsPerAxis - 1;
|
|
}
|
|
|
|
triBins[ 1 ][ k ] = idMath::Ftoi(idMath::Ceil( ( triBounds[ 1 ][ k ] + .5f / snapFractions ) * snapFractions ) );
|
|
triBins[ 1 ][ k ] = ( triBins[ 1 ][ k ] - intMins[ k ] ) / intScale[ k ];
|
|
if ( triBins[ 1 ][ k ] < 0 ) {
|
|
triBins[ 1 ][ k ] = 0;
|
|
} else if ( triBins[ 1 ][ k ] >= binsPerAxis ) {
|
|
triBins[ 1 ][ k ] = binsPerAxis - 1;
|
|
}
|
|
}
|
|
|
|
for ( int k = triBins[ 0 ][ 0 ]; k <= triBins[ 1 ][ 0 ]; k++ ) {
|
|
for ( int l = triBins[ 0 ][ 1 ]; l <= triBins[ 1 ][ 1 ]; l++ ) {
|
|
for ( int m = triBins[ 0 ][ 2 ]; m <= triBins[ 1 ][ 2 ]; m++ ) {
|
|
tri = triangleAllocator.Alloc();
|
|
tri->triIndex = i;
|
|
tri->next = bins[ BinIndex( k, l, m ) ].triangleList;
|
|
bins[ BinIndex( k, l, m ) ].triangleList = tri;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idSurface_Traceable::RayIntersection
|
|
====================
|
|
*/
|
|
bool idSurface_Traceable::RayIntersection( /*idList< int >& tracedTris,*/ const idVec3& start, const idVec3& dir, float& scale, idDrawVert& dv, bool backFaceCull ) const {
|
|
|
|
//tracedTris.Clear();
|
|
|
|
if ( !hash ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !hash->GetBounds().RayIntersection( start, dir, scale ) ) {
|
|
return false;
|
|
}
|
|
|
|
traceCount++;
|
|
|
|
idVec3 point = start + dir * scale;
|
|
|
|
int edgeIndex[ 3 ];
|
|
int side[ 3 ];
|
|
int absEdgeIndex;
|
|
float d;
|
|
sdBitField_Stack sidedness;
|
|
sdBitField_Stack sidednessCalculated;
|
|
idPluecker rayPl, pl;
|
|
|
|
int sizeForEdges = sdBitField_Stack::GetSizeForMaxBits( edges.Num() );
|
|
|
|
sidedness.Init( (int*)_alloca( sizeForEdges * sizeof( int ) ), sizeForEdges );
|
|
sidedness.Clear();
|
|
sidednessCalculated.Init( (int*)_alloca( sizeForEdges * sizeof( int ) ), sizeForEdges );
|
|
sidednessCalculated.Clear();
|
|
|
|
rayPl.FromRay( start, dir );
|
|
|
|
//const int RAY_STEPS = 400;
|
|
const int RAY_STEPS = 1000;
|
|
|
|
idVec3 step = dir * ( 2.f / static_cast< float >( RAY_STEPS ) ) * traceDist;
|
|
|
|
for ( int i = 0; i < RAY_STEPS; i++, point += step ) {
|
|
sdTraceableTriangleHash::hashBin_t* bin = hash->GetHashBin( point );
|
|
|
|
if ( !bin || bin->lastTrace == traceCount ) {
|
|
continue;
|
|
}
|
|
bin->lastTrace = traceCount;
|
|
|
|
for ( sdTraceableTriangleHash::hashTriangle_t* tri = bin->triangleList; tri; tri = tri->next ) {
|
|
|
|
if ( lastTriTrace[ tri->triIndex / 3 ] == traceCount ) {
|
|
continue;
|
|
}
|
|
lastTriTrace[ tri->triIndex / 3 ] = traceCount;
|
|
|
|
//tracedTris.Append( tri->triIndex );
|
|
|
|
for ( int j = 0; j < 3; j++ ) {
|
|
edgeIndex[ j ] = edgeIndexes[ tri->triIndex + j ];
|
|
|
|
absEdgeIndex = abs( edgeIndex[ j ] );
|
|
|
|
if ( !sidednessCalculated.Get( absEdgeIndex ) ) {
|
|
pl.FromLine( verts[ edges[ absEdgeIndex ].verts[ 1 ] ].xyz, verts[ edges[ absEdgeIndex ].verts[ 0 ] ].xyz );
|
|
d = pl.PermutedInnerProduct( rayPl );
|
|
sidedness.Set( absEdgeIndex, FLOATSIGNBITSET( d ) );
|
|
sidednessCalculated.Set( absEdgeIndex );
|
|
}
|
|
|
|
side[ j ] = sidedness.Get( absEdgeIndex ) ^ INTSIGNBITSET( edgeIndex[ j ] );
|
|
}
|
|
|
|
if ( side[ 0 ] & side[ 1 ] & side[ 2 ] ) {
|
|
if ( triPlanes[ tri->triIndex / 3 ].RayIntersection( start, dir, scale ) && !FLOATSIGNBITSET( scale ) ) {
|
|
GenerateIntersectionDrawVert( start + dir * scale, tri->triIndex, dv );
|
|
return true;
|
|
}
|
|
} else if ( !backFaceCull && !(side[ 0 ] | side[ 1 ] | side[ 2 ]) ) {
|
|
if ( triPlanes[ tri->triIndex / 3 ].RayIntersection( start, dir, scale ) && !FLOATSIGNBITSET( scale ) ) {
|
|
GenerateIntersectionDrawVert( start + dir * scale, tri->triIndex, dv );
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
====================
|
|
idSurface_Traceable::RayIntersection
|
|
====================
|
|
*/
|
|
void idSurface_Traceable::GenerateIntersectionDrawVert( const idVec3& intersection, const int intersectedTriIndex, idDrawVert& dv ) const {
|
|
float denom;
|
|
float a, b, c;
|
|
|
|
const idDrawVert* v0 = &verts[ indexes[ intersectedTriIndex + 0 ] ];
|
|
const idDrawVert* v1 = &verts[ indexes[ intersectedTriIndex + 1 ] ];
|
|
const idDrawVert* v2 = &verts[ indexes[ intersectedTriIndex + 2 ] ];
|
|
|
|
// find the barycentric coordinates
|
|
denom = idWinding::TriangleArea( v0->xyz, v1->xyz, v2->xyz );
|
|
|
|
a = idWinding::TriangleArea( intersection, v1->xyz, v2->xyz ) / denom;
|
|
b = idWinding::TriangleArea( v0->xyz, intersection, v2->xyz ) / denom;
|
|
c = idWinding::TriangleArea( v0->xyz, v1->xyz, intersection ) / denom;
|
|
|
|
// generate the interpolated values
|
|
dv.xyz = intersection;
|
|
|
|
// FIXME: SD_USE_DRAWVERT_SIZE_32
|
|
for ( int i = 0; i < 2; i++ ) {
|
|
dv._st[ i ] = a * v0->_st[ i ] + b * v1->_st[ i ] + c * v2->_st[ i ];
|
|
}
|
|
|
|
#if defined( SD_USE_DRAWVERT_SIZE_32 )
|
|
idVec3 n;
|
|
idVec3 n0 = v0->GetNormal();
|
|
idVec3 n1 = v1->GetNormal();
|
|
idVec3 n2 = v2->GetNormal();
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
n[ i ] = a * n0[i] + b * n1[i] + c * n2[i];
|
|
}
|
|
n.Normalize();
|
|
dv.SetNormal( n );
|
|
|
|
idVec3 tgnt;
|
|
idVec3 tgnt0 = v0->GetTangent();
|
|
idVec3 tgnt1 = v1->GetTangent();
|
|
idVec3 tgnt2 = v2->GetTangent();
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
tgnt[ i ] = a * tgnt0[i] + b * tgnt1[i] + c * tgnt2[i];
|
|
}
|
|
tgnt.Normalize();
|
|
dv.SetTangent( tgnt );
|
|
|
|
float s0 = v0->GetBiTangentSign();
|
|
float s1 = v1->GetBiTangentSign();
|
|
float s2 = v2->GetBiTangentSign();
|
|
dv.SetBiTangentSign( a * s0 + b * s1 + c * s2 );
|
|
|
|
#else
|
|
|
|
for ( int i = 0; i < 3; i++ ) {
|
|
dv._normal[ i ] = a * v0->_normal[ i ] + b * v1->_normal[ i ] + c * v2->_normal[ i ];
|
|
}
|
|
dv._normal.Normalize();
|
|
|
|
for ( int i = 0; i < 4; i++ ) {
|
|
dv._tangent[ i ] = a * v0->_tangent[ i ] + b * v1->_tangent[ i ] + c * v2->_tangent[ i ];
|
|
}
|
|
#endif
|
|
|
|
for ( int i = 0; i < 4; i++ ) {
|
|
dv.color[ i ] = idMath::Ftob( a * v0->color[ i ] + b * v1->color[ i ] + c * v2->color[ i ] );
|
|
}
|
|
}
|