123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- 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.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #undef min // windef.h macros
- #undef max
- #include "BoundsTrack.h"
- /*
- We want to do one SIMD compare on 8 short components and know that the bounds
- overlap if all 8 tests pass
- */
- // shortBounds_t is used to track the reference bounds of all entities in a
- // cache-friendly and easy to compare way.
- //
- // To allow all elements to be compared with a single comparison sense, the maxs
- // are stored as negated values.
- //
- // We may need to add a global scale factor to this if there are intersections
- // completely outside +/-32k
- struct shortBounds_t {
- shortBounds_t() {
- SetToEmpty();
- }
- shortBounds_t( const idBounds & b ) {
- SetFromReferenceBounds( b );
- }
- short b[2][4]; // fourth element is just for padding
- idBounds ToFloatBounds() const {
- idBounds f;
- for ( int i = 0 ; i < 3 ; i++ ) {
- f[0][i] = b[0][i];
- f[1][i] = -b[1][i];
- }
- return f;
- }
- bool IntersectsShortBounds( shortBounds_t & comp ) const {
- shortBounds_t test;
- comp.MakeComparisonBounds( test );
- return IntersectsComparisonBounds( test );
- }
- bool IntersectsComparisonBounds( shortBounds_t & test ) const {
- // this can be a single ALTIVEC vcmpgtshR instruction
- return test.b[0][0] > b[0][0]
- && test.b[0][1] > b[0][1]
- && test.b[0][2] > b[0][2]
- && test.b[0][3] > b[0][3]
- && test.b[1][0] > b[1][0]
- && test.b[1][1] > b[1][1]
- && test.b[1][2] > b[1][2]
- && test.b[1][3] > b[1][3];
- }
- void MakeComparisonBounds( shortBounds_t & comp ) const {
- comp.b[0][0] = -b[1][0];
- comp.b[1][0] = -b[0][0];
- comp.b[0][1] = -b[1][1];
- comp.b[1][1] = -b[0][1];
- comp.b[0][2] = -b[1][2];
- comp.b[1][2] = -b[0][2];
- comp.b[0][3] = 0x7fff;
- comp.b[1][3] = 0x7fff;
- }
- void SetFromReferenceBounds( const idBounds & set ) {
- // the maxs are stored negated
- for ( int i = 0 ; i < 3 ; i++ ) {
- int minv = floor( set[0][i] );
- b[0][i] = std::max( -32768, minv );
- int maxv = -ceil( set[1][i] );
- b[1][i] = std::min( 32767, maxv );
- }
- b[0][3] = b[1][3] = 0;
- }
- void SetToEmpty() {
- // this will always fail the comparison
- for ( int i = 0 ; i < 2 ; i++ ) {
- for ( int j = 0 ; j < 4 ; j++ ) {
- b[i][j] = 0x7fff;
- }
- }
- }
- };
- // pure function
- int FindBoundsIntersectionsTEST(
- const shortBounds_t testBounds,
- const shortBounds_t * const boundsList,
- const int numBounds,
- int * const returnedList ) {
- int hits = 0;
- idBounds testF = testBounds.ToFloatBounds();
- for ( int i = 0 ; i < numBounds ; i++ ) {
- idBounds listF = boundsList[i].ToFloatBounds();
- if ( testF.IntersectsBounds( listF ) ) {
- returnedList[hits++] = i;
- }
- }
- return hits;
- }
- // pure function
- int FindBoundsIntersectionsSimSIMD(
- const shortBounds_t testBounds,
- const shortBounds_t * const boundsList,
- const int numBounds,
- int * const returnedList ) {
- shortBounds_t compareBounds;
- testBounds.MakeComparisonBounds( compareBounds );
- int hits = 0;
- for ( int i = 0 ; i < numBounds ; i++ ) {
- const shortBounds_t & listBounds = boundsList[i];
- bool compare[8];
- int count = 0;
- for ( int j = 0 ; j < 8 ; j++ ) {
- if ( ((short *)&compareBounds)[j] >= ((short *)&listBounds)[j] ) {
- compare[j] = true;
- count++;
- } else {
- compare[j] = false;
- }
- }
- if ( count == 8 ) {
- returnedList[hits++] = i;
- }
- }
- return hits;
- }
- idBoundsTrack::idBoundsTrack() {
- boundsList = (shortBounds_t *)Mem_Alloc( MAX_BOUNDS_TRACK_INDEXES * sizeof( *boundsList ), TAG_RENDER );
- ClearAll();
- }
- idBoundsTrack::~idBoundsTrack() {
- Mem_Free( boundsList );
- }
- void idBoundsTrack::ClearAll() {
- maxIndex = 0;
- for ( int i = 0 ; i < MAX_BOUNDS_TRACK_INDEXES ; i++ ) {
- ClearIndex( i );
- }
- }
- void idBoundsTrack::SetIndex( const int index, const idBounds & bounds ) {
- assert( (unsigned)index < MAX_BOUNDS_TRACK_INDEXES );
- maxIndex = std::max( maxIndex, index+1);
- boundsList[index].SetFromReferenceBounds( bounds );
- }
- void idBoundsTrack::ClearIndex( const int index ) {
- assert( (unsigned)index < MAX_BOUNDS_TRACK_INDEXES );
- boundsList[index].SetToEmpty();
- }
- int idBoundsTrack::FindIntersections( const idBounds & testBounds, int intersectedIndexes[ MAX_BOUNDS_TRACK_INDEXES ] ) const {
- const shortBounds_t shortTestBounds( testBounds );
- return FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes );
- }
- void idBoundsTrack::Test() {
- ClearAll();
- idRandom r;
- for ( int i = 0 ; i < 1800 ; i++ ) {
- idBounds b;
- for ( int j = 0 ; j < 3 ; j++ ) {
- b[0][j] = r.RandomInt( 20000 ) - 10000;
- b[1][j] = b[0][j] + r.RandomInt( 1000 );
- }
- SetIndex( i, b );
- }
- const idBounds testBounds( idVec3( -1000, 2000, -3000 ), idVec3( 1500, 4500, -500 ) );
- SetIndex( 1800, testBounds );
- SetIndex( 0, testBounds );
- const shortBounds_t shortTestBounds( testBounds );
- int intersectedIndexes1[ MAX_BOUNDS_TRACK_INDEXES ];
- const int numHits1 = FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
- int intersectedIndexes2[ MAX_BOUNDS_TRACK_INDEXES ];
- const int numHits2 = FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
- idLib::Printf( "%i intersections\n", numHits1 );
- if ( numHits1 != numHits2 ) {
- idLib::Printf( "different results\n" );
- } else {
- for ( int i = 0 ; i < numHits1 ; i++ ) {
- if ( intersectedIndexes1[i] != intersectedIndexes2[i] ) {
- idLib::Printf( "different results\n" );
- break;
- }
- }
- }
- // run again for debugging failure
- FindBoundsIntersectionsTEST( shortTestBounds, boundsList, maxIndex, intersectedIndexes1 );
- FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
- // timing
- const int64 start = Sys_Microseconds();
- for ( int i = 0 ; i < 40 ; i++ ) {
- FindBoundsIntersectionsSimSIMD( shortTestBounds, boundsList, maxIndex, intersectedIndexes2 );
- }
- const int64 stop = Sys_Microseconds();
- idLib::Printf( "%i microseconds for 40 itterations\n", stop - start );
- }
- class interactionPair_t {
- int entityIndex;
- int lightIndex;
- };
- /*
- keep a sorted list of static interactions and interactions already generated this frame?
- determine if the light needs more exact culling because it is rotated or a spot light
- for each entity on the bounds intersection list
- if entity is not directly visible, determine if it can cast a shadow into the view
- if the light center is in-frustum
- and the entity bounds is out-of-frustum, it can't contribue
- else the light center is off-frustum
- 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
- if a static interaction exists
- continue
- possibly perform more exact refernce bounds to rotated or spot light
- create an interaction pair and add it to the list
- all models will have an interaction with light -1 for ambient surface
- sort the interaction list by model
- do
- if the model is dynamic, create it
- add the ambient surface and skip interaction -1
- for all interactions
- check for static interaction
- check for current-frame interaction
- else create shadow for this light
- */
|