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 */