DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

BoundsTrack.cpp (8698B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 
     33 #undef min			// windef.h macros
     34 #undef max
     35 
     36 #include "BoundsTrack.h"
     37 
     38 /*
     39 
     40 We want to do one SIMD compare on 8 short components and know that the bounds
     41 overlap if all 8 tests pass
     42 
     43 */
     44 
     45 // shortBounds_t is used to track the reference bounds of all entities in a
     46 // cache-friendly and easy to compare way.
     47 //
     48 // To allow all elements to be compared with a single comparison sense, the maxs
     49 // are stored as negated values.
     50 //
     51 // We may need to add a global scale factor to this if there are intersections
     52 // completely outside +/-32k
     53 struct shortBounds_t {
     54 	shortBounds_t() {
     55 		SetToEmpty();
     56 	}
     57 
     58 	shortBounds_t( const idBounds & b  ) {
     59 		SetFromReferenceBounds( b );
     60 	}
     61 
     62 	short	b[2][4];		// fourth element is just for padding
     63 
     64 	idBounds ToFloatBounds() const {
     65 		idBounds	f;
     66 		for ( int i = 0 ; i < 3 ; i++ ) {
     67 			f[0][i] = b[0][i];
     68 			f[1][i] = -b[1][i];
     69 		}
     70 		return f;
     71 	}
     72 
     73 	bool	IntersectsShortBounds( shortBounds_t & comp ) const {
     74 		shortBounds_t test;
     75 		comp.MakeComparisonBounds( test );
     76 		return IntersectsComparisonBounds( test );
     77 	}
     78 
     79 	bool	IntersectsComparisonBounds( shortBounds_t & test ) const {
     80 		// this can be a single ALTIVEC vcmpgtshR instruction
     81 		return test.b[0][0] > b[0][0]
     82 			&& test.b[0][1] > b[0][1]
     83 			&& test.b[0][2] > b[0][2]
     84 			&& test.b[0][3] > b[0][3]
     85 			&& test.b[1][0] > b[1][0]
     86 			&& test.b[1][1] > b[1][1]
     87 			&& test.b[1][2] > b[1][2]
     88 			&& test.b[1][3] > b[1][3];
     89 	}
     90 
     91 	void MakeComparisonBounds( shortBounds_t & comp ) const {
     92 		comp.b[0][0] = -b[1][0];
     93 		comp.b[1][0] = -b[0][0];
     94 		comp.b[0][1] = -b[1][1];
     95 		comp.b[1][1] = -b[0][1];
     96 		comp.b[0][2] = -b[1][2];
     97 		comp.b[1][2] = -b[0][2];
     98 		comp.b[0][3] = 0x7fff;
     99 		comp.b[1][3] = 0x7fff;
    100 	}
    101 
    102 	void SetFromReferenceBounds( const idBounds & set ) {
    103 		// the maxs are stored negated
    104 		for ( int i = 0 ; i < 3 ; i++ ) {
    105 			int minv = floor( set[0][i] );
    106 			b[0][i] = std::max( -32768, minv );
    107 			int maxv = -ceil( set[1][i] );
    108 			b[1][i] = std::min( 32767, maxv );
    109 		}
    110 		b[0][3] = b[1][3] = 0;
    111 	}
    112 
    113 	void SetToEmpty() {
    114 		// this will always fail the comparison
    115 		for ( int i = 0 ; i < 2 ; i++ ) {
    116 			for ( int j = 0 ; j < 4 ; j++ ) {
    117 				b[i][j] = 0x7fff;
    118 			}
    119 		}
    120 	}
    121 };
    122 
    123 
    124 
    125 // pure function
    126 int FindBoundsIntersectionsTEST( 
    127 	const shortBounds_t			testBounds,
    128 	const shortBounds_t * const	boundsList,
    129 	const int					numBounds,
    130 	int * const					returnedList ) {
    131 
    132 	int hits = 0;
    133 	idBounds	testF = testBounds.ToFloatBounds();
    134 	for ( int i = 0 ; i < numBounds ; i++ ) {
    135 		idBounds	listF = boundsList[i].ToFloatBounds();
    136 		if ( testF.IntersectsBounds( listF ) ) {
    137 			returnedList[hits++] = i;
    138 		}
    139 	}
    140 	return hits;
    141 }
    142 
    143 // pure function
    144 int FindBoundsIntersectionsSimSIMD( 
    145 	const shortBounds_t			testBounds,
    146 	const shortBounds_t * const	boundsList,
    147 	const int					numBounds,
    148 	int * const					returnedList ) {
    149 
    150 	shortBounds_t	compareBounds;
    151 	testBounds.MakeComparisonBounds( compareBounds );
    152 
    153 	int hits = 0;
    154 	for ( int i = 0 ; i < numBounds ; i++ ) {
    155 		const shortBounds_t & listBounds = boundsList[i];
    156 		bool	compare[8];
    157 		int		count = 0;
    158 		for ( int j = 0 ; j < 8 ; j++ ) {
    159 			if ( ((short *)&compareBounds)[j] >= ((short *)&listBounds)[j] ) {
    160 				compare[j] = true;
    161 				count++;
    162 			} else {
    163 				compare[j] = false;
    164 			}
    165 		}
    166 		if ( count == 8 ) {
    167 			returnedList[hits++] = i;
    168 		}
    169 	}
    170 	return hits;
    171 }
    172 
    173 
    174 
    175 idBoundsTrack::idBoundsTrack() {
    176 	boundsList = (shortBounds_t *)Mem_Alloc( MAX_BOUNDS_TRACK_INDEXES * sizeof( *boundsList ), TAG_RENDER );
    177 	ClearAll();
    178 }
    179 
    180 idBoundsTrack::~idBoundsTrack() {
    181 	Mem_Free( boundsList );
    182 }
    183 
    184 void idBoundsTrack::ClearAll() {
    185 	maxIndex = 0;
    186 	for ( int i = 0 ; i < MAX_BOUNDS_TRACK_INDEXES ; i++ ) {
    187 		ClearIndex( i );
    188 	}
    189 }
    190 
    191 void	idBoundsTrack::SetIndex( const int index, const idBounds & bounds ) {
    192 	assert( (unsigned)index < MAX_BOUNDS_TRACK_INDEXES );
    193 	maxIndex = std::max( maxIndex, index+1);
    194 	boundsList[index].SetFromReferenceBounds( bounds );
    195 }
    196 
    197 void	idBoundsTrack::ClearIndex( const int index ) {
    198 	assert( (unsigned)index < MAX_BOUNDS_TRACK_INDEXES );
    199 	boundsList[index].SetToEmpty();
    200 }
    201 
    202 int		idBoundsTrack::FindIntersections( const idBounds & testBounds, int intersectedIndexes[ MAX_BOUNDS_TRACK_INDEXES ] ) const {
    203 	const shortBounds_t	shortTestBounds( testBounds );
    204 	return FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes );
    205 }
    206 
    207 void	idBoundsTrack::Test() {
    208 	ClearAll();
    209 	idRandom	r;
    210 
    211 	for ( int i = 0 ; i < 1800 ; i++ ) {
    212 		idBounds b;
    213 		for ( int j = 0 ; j < 3 ; j++ ) {
    214 			b[0][j] = r.RandomInt( 20000 ) - 10000;
    215 			b[1][j] = b[0][j] + r.RandomInt( 1000 );
    216 		}
    217 		SetIndex( i, b );
    218 	}
    219 
    220 	const idBounds testBounds( idVec3( -1000, 2000, -3000 ), idVec3( 1500, 4500, -500 ) );
    221 	SetIndex( 1800, testBounds );
    222 	SetIndex( 0, testBounds );
    223 
    224 	const shortBounds_t	shortTestBounds( testBounds );
    225 
    226 	int intersectedIndexes1[ MAX_BOUNDS_TRACK_INDEXES ];
    227 	const int numHits1 = FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
    228 
    229 	int intersectedIndexes2[ MAX_BOUNDS_TRACK_INDEXES ];
    230 	const int numHits2 = FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
    231 	idLib::Printf( "%i intersections\n", numHits1 );
    232 	if ( numHits1 != numHits2 ) {
    233 		idLib::Printf( "different results\n" );
    234 	} else {
    235 		for ( int i = 0 ; i < numHits1 ; i++ ) {
    236 			if ( intersectedIndexes1[i] != intersectedIndexes2[i] ) {
    237 				idLib::Printf( "different results\n" );
    238 				break;
    239 			}
    240 		}
    241 	}
    242 
    243 	// run again for debugging failure
    244 	FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
    245 	FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
    246 
    247 	// timing
    248 	const int64 start = Sys_Microseconds();
    249 	for ( int i = 0 ; i < 40 ; i++ ) {
    250 		FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
    251 	}
    252 	const int64 stop = Sys_Microseconds();
    253 	idLib::Printf( "%i microseconds for 40 itterations\n", stop - start );
    254 }
    255 
    256 
    257 
    258 class interactionPair_t {
    259 	int		entityIndex;
    260 	int		lightIndex;
    261 };
    262 
    263 /*
    264 
    265 keep a sorted list of static interactions and interactions already generated this frame?
    266 
    267 determine if the light needs more exact culling because it is rotated or a spot light
    268 for each entity on the bounds intersection list
    269 	if entity is not directly visible, determine if it can cast a shadow into the view
    270 		if the light center is in-frustum 
    271 			and the entity bounds is out-of-frustum, it can't contribue
    272 		else the light center is off-frustum
    273 			if any of the view frustum planes can be moved out to the light center and the entity bounds is still outside it, it can't contribute
    274 	if a static interaction exists
    275 		continue
    276 	possibly perform more exact refernce bounds to rotated or spot light
    277 
    278 	create an interaction pair and add it to the list
    279 
    280 
    281 all models will have an interaction with light -1 for ambient surface
    282 sort the interaction list by model
    283 do
    284 	if the model is dynamic, create it
    285 	add the ambient surface and skip interaction -1
    286 	for all interactions
    287 		check for static interaction
    288 		check for current-frame interaction
    289 		else create shadow for this light
    290 
    291 */