123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 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 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.
- ===========================================================================
- */
- #include "../precompiled.h"
- #pragma hdrstop
- //#define FRUSTUM_DEBUG
- /*
- bit 0 = min x
- bit 1 = max x
- bit 2 = min y
- bit 3 = max y
- bit 4 = min z
- bit 5 = max z
- */
- static int boxVertPlanes[8] = {
- ( (1<<0) | (1<<2) | (1<<4) ),
- ( (1<<1) | (1<<2) | (1<<4) ),
- ( (1<<1) | (1<<3) | (1<<4) ),
- ( (1<<0) | (1<<3) | (1<<4) ),
- ( (1<<0) | (1<<2) | (1<<5) ),
- ( (1<<1) | (1<<2) | (1<<5) ),
- ( (1<<1) | (1<<3) | (1<<5) ),
- ( (1<<0) | (1<<3) | (1<<5) ),
- };
- /*
- ============
- BoxToPoints
- ============
- */
- void BoxToPoints( const idVec3 ¢er, const idVec3 &extents, const idMat3 &axis, idVec3 points[8] ) {
- idMat3 ax;
- idVec3 temp[4];
- ax[0] = extents[0] * axis[0];
- ax[1] = extents[1] * axis[1];
- ax[2] = extents[2] * axis[2];
- temp[0] = center - ax[0];
- temp[1] = center + ax[0];
- temp[2] = ax[1] - ax[2];
- temp[3] = ax[1] + ax[2];
- points[0] = temp[0] - temp[3];
- points[1] = temp[1] - temp[3];
- points[2] = temp[1] + temp[2];
- points[3] = temp[0] + temp[2];
- points[4] = temp[0] - temp[2];
- points[5] = temp[1] - temp[2];
- points[6] = temp[1] + temp[3];
- points[7] = temp[0] + temp[3];
- }
- /*
- ================
- idFrustum::PlaneDistance
- ================
- */
- float idFrustum::PlaneDistance( const idPlane &plane ) const {
- float min, max;
- AxisProjection( plane.Normal(), min, max );
- if ( min + plane[3] > 0.0f ) {
- return min + plane[3];
- }
- if ( max + plane[3] < 0.0f ) {
- return max + plane[3];
- }
- return 0.0f;
- }
- /*
- ================
- idFrustum::PlaneSide
- ================
- */
- int idFrustum::PlaneSide( const idPlane &plane, const float epsilon ) const {
- float min, max;
- AxisProjection( plane.Normal(), min, max );
- if ( min + plane[3] > epsilon ) {
- return PLANESIDE_FRONT;
- }
- if ( max + plane[3] < epsilon ) {
- return PLANESIDE_BACK;
- }
- return PLANESIDE_CROSS;
- }
- /*
- ============
- idFrustum::CullPoint
- ============
- */
- bool idFrustum::CullPoint( const idVec3 &point ) const {
- idVec3 p;
- float scale;
- // transform point to frustum space
- p = ( point - origin ) * axis.Transpose();
- // test whether or not the point is within the frustum
- if ( p.x < dNear || p.x > dFar ) {
- return true;
- }
- scale = p.x * invFar;
- if ( idMath::Fabs( p.y ) > dLeft * scale ) {
- return true;
- }
- if ( idMath::Fabs( p.z ) > dUp * scale ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::CullLocalBox
- Tests if any of the planes of the frustum can be used as a separating plane.
- 3 muls best case
- 25 muls worst case
- ============
- */
- bool idFrustum::CullLocalBox( const idVec3 &localOrigin, const idVec3 &extents, const idMat3 &localAxis ) const {
- float d1, d2;
- idVec3 testOrigin;
- idMat3 testAxis;
- // near plane
- d1 = dNear - localOrigin.x;
- d2 = idMath::Fabs( extents[0] * localAxis[0][0] ) +
- idMath::Fabs( extents[1] * localAxis[1][0] ) +
- idMath::Fabs( extents[2] * localAxis[2][0] );
- if ( d1 - d2 > 0.0f ) {
- return true;
- }
- // far plane
- d1 = localOrigin.x - dFar;
- if ( d1 - d2 > 0.0f ) {
- return true;
- }
- testOrigin = localOrigin;
- testAxis = localAxis;
- if ( testOrigin.y < 0.0f ) {
- testOrigin.y = -testOrigin.y;
- testAxis[0][1] = -testAxis[0][1];
- testAxis[1][1] = -testAxis[1][1];
- testAxis[2][1] = -testAxis[2][1];
- }
- // test left/right planes
- d1 = dFar * testOrigin.y - dLeft * testOrigin.x;
- d2 = idMath::Fabs( extents[0] * ( dFar * testAxis[0][1] - dLeft * testAxis[0][0] ) ) +
- idMath::Fabs( extents[1] * ( dFar * testAxis[1][1] - dLeft * testAxis[1][0] ) ) +
- idMath::Fabs( extents[2] * ( dFar * testAxis[2][1] - dLeft * testAxis[2][0] ) );
- if ( d1 - d2 > 0.0f ) {
- return true;
- }
- if ( testOrigin.z < 0.0f ) {
- testOrigin.z = -testOrigin.z;
- testAxis[0][2] = -testAxis[0][2];
- testAxis[1][2] = -testAxis[1][2];
- testAxis[2][2] = -testAxis[2][2];
- }
- // test up/down planes
- d1 = dFar * testOrigin.z - dUp * testOrigin.x;
- d2 = idMath::Fabs( extents[0] * ( dFar * testAxis[0][2] - dUp * testAxis[0][0] ) ) +
- idMath::Fabs( extents[1] * ( dFar * testAxis[1][2] - dUp * testAxis[1][0] ) ) +
- idMath::Fabs( extents[2] * ( dFar * testAxis[2][2] - dUp * testAxis[2][0] ) );
- if ( d1 - d2 > 0.0f ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::CullBounds
- Tests if any of the planes of the frustum can be used as a separating plane.
- 24 muls best case
- 37 muls worst case
- ============
- */
- bool idFrustum::CullBounds( const idBounds &bounds ) const {
- idVec3 localOrigin, center, extents;
- idMat3 localAxis;
- center = ( bounds[0] + bounds[1] ) * 0.5f;
- extents = bounds[1] - center;
- // transform the bounds into the space of this frustum
- localOrigin = ( center - origin ) * axis.Transpose();
- localAxis = axis.Transpose();
- return CullLocalBox( localOrigin, extents, localAxis );
- }
- /*
- ============
- idFrustum::CullBounds
- Tests if any of the planes of the frustum can be used as a separating plane.
- 39 muls best case
- 61 muls worst case
- ============
- */
- bool idFrustum::CullBox( const idBox &box ) const {
- idVec3 localOrigin;
- idMat3 localAxis;
- // transform the box into the space of this frustum
- localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
- localAxis = box.GetAxis() * axis.Transpose();
- return CullLocalBox( localOrigin, box.GetExtents(), localAxis );
- }
- /*
- ============
- idFrustum::CullSphere
- Tests if any of the planes of the frustum can be used as a separating plane.
- 9 muls best case
- 21 muls worst case
- ============
- */
- bool idFrustum::CullSphere( const idSphere &sphere ) const {
- float d, r, rs, sFar;
- idVec3 center;
- center = ( sphere.GetOrigin() - origin ) * axis.Transpose();
- r = sphere.GetRadius();
- // test near plane
- if ( dNear - center.x > r ) {
- return true;
- }
- // test far plane
- if ( center.x - dFar > r ) {
- return true;
- }
- rs = r * r;
- sFar = dFar * dFar;
- // test left/right planes
- d = dFar * idMath::Fabs( center.y ) - dLeft * center.x;
- if ( ( d * d ) > rs * ( sFar + dLeft * dLeft ) ) {
- return true;
- }
- // test up/down planes
- d = dFar * idMath::Fabs( center.z ) - dUp * center.x;
- if ( ( d * d ) > rs * ( sFar + dUp * dUp ) ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::CullLocalFrustum
- Tests if any of the planes of this frustum can be used as a separating plane.
- 0 muls best case
- 30 muls worst case
- ============
- */
- bool idFrustum::CullLocalFrustum( const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const {
- int index;
- float dx, dy, dz, leftScale, upScale;
- // test near plane
- dy = -localFrustum.axis[1].x;
- dz = -localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].x < dNear ) {
- return true;
- }
- // test far plane
- dy = localFrustum.axis[1].x;
- dz = localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].x > dFar ) {
- return true;
- }
- leftScale = dLeft * invFar;
- // test left plane
- dy = dFar * localFrustum.axis[1].y - dLeft * localFrustum.axis[1].x;
- dz = dFar * localFrustum.axis[2].y - dLeft * localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = dFar * cornerVecs[index].y - dLeft * cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].y > indexPoints[index].x * leftScale ) {
- return true;
- }
- // test right plane
- dy = -dFar * localFrustum.axis[1].y - dLeft * localFrustum.axis[1].x;
- dz = -dFar * localFrustum.axis[2].y - dLeft * localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -dFar * cornerVecs[index].y - dLeft * cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].y < -indexPoints[index].x * leftScale ) {
- return true;
- }
- upScale = dUp * invFar;
- // test up plane
- dy = dFar * localFrustum.axis[1].z - dUp * localFrustum.axis[1].x;
- dz = dFar * localFrustum.axis[2].z - dUp * localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = dFar * cornerVecs[index].z - dUp * cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].z > indexPoints[index].x * upScale ) {
- return true;
- }
- // test down plane
- dy = -dFar * localFrustum.axis[1].z - dUp * localFrustum.axis[1].x;
- dz = -dFar * localFrustum.axis[2].z - dUp * localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -dFar * cornerVecs[index].z - dUp * cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].z < -indexPoints[index].x * upScale ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::CullFrustum
- Tests if any of the planes of this frustum can be used as a separating plane.
- 58 muls best case
- 88 muls worst case
- ============
- */
- bool idFrustum::CullFrustum( const idFrustum &frustum ) const {
- idFrustum localFrustum;
- idVec3 indexPoints[8], cornerVecs[4];
- // transform the given frustum into the space of this frustum
- localFrustum = frustum;
- localFrustum.origin = ( frustum.origin - origin ) * axis.Transpose();
- localFrustum.axis = frustum.axis * axis.Transpose();
- localFrustum.ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- return CullLocalFrustum( localFrustum, indexPoints, cornerVecs );
- }
- /*
- ============
- idFrustum::CullLocalWinding
- ============
- */
- bool idFrustum::CullLocalWinding( const idVec3 *points, const int numPoints, int *pointCull ) const {
- int i, pCull, culled;
- float leftScale, upScale;
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- culled = -1;
- for ( i = 0; i < numPoints; i++ ) {
- const idVec3 &p = points[i];
- pCull = 0;
- if ( p.x < dNear ) {
- pCull = 1;
- }
- else if ( p.x > dFar ) {
- pCull = 2;
- }
- if ( idMath::Fabs( p.y ) > p.x * leftScale ) {
- pCull |= 4 << FLOATSIGNBITSET( p.y );
- }
- if ( idMath::Fabs( p.z ) > p.x * upScale ) {
- pCull |= 16 << FLOATSIGNBITSET( p.z );
- }
- culled &= pCull;
- pointCull[i] = pCull;
- }
- return ( culled != 0 );
- }
- /*
- ============
- idFrustum::CullWinding
- ============
- */
- bool idFrustum::CullWinding( const idWinding &winding ) const {
- int i, *pointCull;
- idVec3 *localPoints;
- idMat3 transpose;
- localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
- pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
- transpose = axis.Transpose();
- for ( i = 0; i < winding.GetNumPoints(); i++ ) {
- localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
- }
- return CullLocalWinding( localPoints, winding.GetNumPoints(), pointCull );
- }
- /*
- ============
- idFrustum::BoundsCullLocalFrustum
- Tests if any of the bounding box planes can be used as a separating plane.
- ============
- */
- bool idFrustum::BoundsCullLocalFrustum( const idBounds &bounds, const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const {
- int index;
- float dx, dy, dz;
- dy = -localFrustum.axis[1].x;
- dz = -localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].x < bounds[0].x ) {
- return true;
- }
- dy = localFrustum.axis[1].x;
- dz = localFrustum.axis[2].x;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = cornerVecs[index].x;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].x > bounds[1].x ) {
- return true;
- }
- dy = -localFrustum.axis[1].y;
- dz = -localFrustum.axis[2].y;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -cornerVecs[index].y;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].y < bounds[0].y ) {
- return true;
- }
- dy = localFrustum.axis[1].y;
- dz = localFrustum.axis[2].y;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = cornerVecs[index].y;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].y > bounds[1].y ) {
- return true;
- }
- dy = -localFrustum.axis[1].z;
- dz = -localFrustum.axis[2].z;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = -cornerVecs[index].z;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].z < bounds[0].z ) {
- return true;
- }
- dy = localFrustum.axis[1].z;
- dz = localFrustum.axis[2].z;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = cornerVecs[index].z;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- if ( indexPoints[index].z > bounds[1].z ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::LocalLineIntersection
- 7 divs
- 30 muls
- ============
- */
- bool idFrustum::LocalLineIntersection( const idVec3 &start, const idVec3 &end ) const {
- idVec3 dir;
- float d1, d2, fstart, fend, lstart, lend, f, x;
- float leftScale, upScale;
- int startInside = 1;
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- dir = end - start;
- // test near plane
- if ( dNear > 0.0f ) {
- d1 = dNear - start.x;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = dNear - end.x;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- if ( idMath::Fabs( start.y + f * dir.y ) <= dNear * leftScale ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= dNear * upScale ) {
- return true;
- }
- }
- }
- }
- }
- // test far plane
- d1 = start.x - dFar;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = end.x - dFar;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- if ( idMath::Fabs( start.y + f * dir.y ) <= dFar * leftScale ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= dFar * upScale ) {
- return true;
- }
- }
- }
- }
- fstart = dFar * start.y;
- fend = dFar * end.y;
- lstart = dLeft * start.x;
- lend = dLeft * end.x;
- // test left plane
- d1 = fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = fend - lend;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
- return true;
- }
- }
- }
- }
- // test right plane
- d1 = -fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = -fend - lend;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
- return true;
- }
- }
- }
- }
- fstart = dFar * start.z;
- fend = dFar * end.z;
- lstart = dUp * start.x;
- lend = dUp * end.x;
- // test up plane
- d1 = fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = fend - lend;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
- return true;
- }
- }
- }
- }
- // test down plane
- d1 = -fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- if ( FLOATNOTZERO( d1 ) ) {
- d2 = -fend - lend;
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
- return true;
- }
- }
- }
- }
- return ( startInside != 0 );
- }
- /*
- ============
- idFrustum::LocalRayIntersection
- Returns true if the ray starts inside the frustum.
- If there was an intersection scale1 <= scale2
- ============
- */
- bool idFrustum::LocalRayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
- idVec3 end;
- float d1, d2, fstart, fend, lstart, lend, f, x;
- float leftScale, upScale;
- int startInside = 1;
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- end = start + dir;
- scale1 = idMath::INFINITY;
- scale2 = -idMath::INFINITY;
- // test near plane
- if ( dNear > 0.0f ) {
- d1 = dNear - start.x;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = dNear - end.x;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- if ( idMath::Fabs( start.y + f * dir.y ) <= dNear * leftScale ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= dNear * upScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- }
- // test far plane
- d1 = start.x - dFar;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = end.x - dFar;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- if ( idMath::Fabs( start.y + f * dir.y ) <= dFar * leftScale ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= dFar * upScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- fstart = dFar * start.y;
- fend = dFar * end.y;
- lstart = dLeft * start.x;
- lend = dLeft * end.x;
- // test left plane
- d1 = fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = fend - lend;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- // test right plane
- d1 = -fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = -fend - lend;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- fstart = dFar * start.z;
- fend = dFar * end.z;
- lstart = dUp * start.x;
- lend = dUp * end.x;
- // test up plane
- d1 = fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = fend - lend;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- // test down plane
- d1 = -fstart - lstart;
- startInside &= FLOATSIGNBITSET( d1 );
- d2 = -fend - lend;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- x = start.x + f * dir.x;
- if ( x >= dNear && x <= dFar ) {
- if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- return ( startInside != 0 );
- }
- /*
- ============
- idFrustum::ContainsPoint
- ============
- */
- bool idFrustum::ContainsPoint( const idVec3 &point ) const {
- return !CullPoint( point );
- }
- /*
- ============
- idFrustum::LocalFrustumIntersectsFrustum
- ============
- */
- bool idFrustum::LocalFrustumIntersectsFrustum( const idVec3 points[8], const bool testFirstSide ) const {
- int i;
- // test if any edges of the other frustum intersect this frustum
- for ( i = 0; i < 4; i++ ) {
- if ( LocalLineIntersection( points[i], points[4+i] ) ) {
- return true;
- }
- }
- if ( testFirstSide ) {
- for ( i = 0; i < 4; i++ ) {
- if ( LocalLineIntersection( points[i], points[(i+1)&3] ) ) {
- return true;
- }
- }
- }
- for ( i = 0; i < 4; i++ ) {
- if ( LocalLineIntersection( points[4+i], points[4+((i+1)&3)] ) ) {
- return true;
- }
- }
- return false;
- }
- /*
- ============
- idFrustum::LocalFrustumIntersectsBounds
- ============
- */
- bool idFrustum::LocalFrustumIntersectsBounds( const idVec3 points[8], const idBounds &bounds ) const {
- int i;
- // test if any edges of the other frustum intersect this frustum
- for ( i = 0; i < 4; i++ ) {
- if ( bounds.LineIntersection( points[i], points[4+i] ) ) {
- return true;
- }
- }
- if ( dNear > 0.0f ) {
- for ( i = 0; i < 4; i++ ) {
- if ( bounds.LineIntersection( points[i], points[(i+1)&3] ) ) {
- return true;
- }
- }
- }
- for ( i = 0; i < 4; i++ ) {
- if ( bounds.LineIntersection( points[4+i], points[4+((i+1)&3)] ) ) {
- return true;
- }
- }
- return false;
- }
- /*
- ============
- idFrustum::IntersectsBounds
- ============
- */
- bool idFrustum::IntersectsBounds( const idBounds &bounds ) const {
- idVec3 localOrigin, center, extents;
- idMat3 localAxis;
- center = ( bounds[0] + bounds[1] ) * 0.5f;
- extents = bounds[1] - center;
- localOrigin = ( center - origin ) * axis.Transpose();
- localAxis = axis.Transpose();
- if ( CullLocalBox( localOrigin, extents, localAxis ) ) {
- return false;
- }
- idVec3 indexPoints[8], cornerVecs[4];
- ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- if ( BoundsCullLocalFrustum( bounds, *this, indexPoints, cornerVecs ) ) {
- return false;
- }
- idSwap( indexPoints[2], indexPoints[3] );
- idSwap( indexPoints[6], indexPoints[7] );
- if ( LocalFrustumIntersectsBounds( indexPoints, bounds ) ) {
- return true;
- }
- BoxToPoints( localOrigin, extents, localAxis, indexPoints );
- if ( LocalFrustumIntersectsFrustum( indexPoints, true ) ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::IntersectsBox
- ============
- */
- bool idFrustum::IntersectsBox( const idBox &box ) const {
- idVec3 localOrigin;
- idMat3 localAxis;
- localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
- localAxis = box.GetAxis() * axis.Transpose();
- if ( CullLocalBox( localOrigin, box.GetExtents(), localAxis ) ) {
- return false;
- }
- idVec3 indexPoints[8], cornerVecs[4];
- idFrustum localFrustum;
- localFrustum = *this;
- localFrustum.origin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
- localFrustum.axis = axis * box.GetAxis().Transpose();
- localFrustum.ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- if ( BoundsCullLocalFrustum( idBounds( -box.GetExtents(), box.GetExtents() ), localFrustum, indexPoints, cornerVecs ) ) {
- return false;
- }
- idSwap( indexPoints[2], indexPoints[3] );
- idSwap( indexPoints[6], indexPoints[7] );
- if ( LocalFrustumIntersectsBounds( indexPoints, idBounds( -box.GetExtents(), box.GetExtents() ) ) ) {
- return true;
- }
- BoxToPoints( localOrigin, box.GetExtents(), localAxis, indexPoints );
- if ( LocalFrustumIntersectsFrustum( indexPoints, true ) ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::IntersectsSphere
- FIXME: test this
- ============
- */
- #define VORONOI_INDEX( x, y, z ) ( x + y * 3 + z * 9 )
- bool idFrustum::IntersectsSphere( const idSphere &sphere ) const {
- int index, x, y, z;
- float scale, r, d;
- idVec3 p, dir, points[8];
- if ( CullSphere( sphere ) ) {
- return false;
- }
- x = y = z = 0;
- dir.Zero();
- p = ( sphere.GetOrigin() - origin ) * axis.Transpose();
- if ( p.x <= dNear ) {
- scale = dNear * invFar;
- dir.y = idMath::Fabs( p.y ) - dLeft * scale;
- dir.z = idMath::Fabs( p.z ) - dUp * scale;
- }
- else if ( p.x >= dFar ) {
- dir.y = idMath::Fabs( p.y ) - dLeft;
- dir.z = idMath::Fabs( p.z ) - dUp;
- }
- else {
- scale = p.x * invFar;
- dir.y = idMath::Fabs( p.y ) - dLeft * scale;
- dir.z = idMath::Fabs( p.z ) - dUp * scale;
- }
- if ( dir.y > 0.0f ) {
- y = ( 1 + FLOATSIGNBITNOTSET( p.y ) );
- }
- if ( dir.z > 0.0f ) {
- z = ( 1 + FLOATSIGNBITNOTSET( p.z ) );
- }
- if ( p.x < dNear ) {
- scale = dLeft * dNear * invFar;
- if ( p.x < dNear + ( scale - p.y ) * scale * invFar ) {
- scale = dUp * dNear * invFar;
- if ( p.x < dNear + ( scale - p.z ) * scale * invFar ) {
- x = 1;
- }
- }
- }
- else {
- if ( p.x > dFar ) {
- x = 2;
- }
- else if ( p.x > dFar + ( dLeft - p.y ) * dLeft * invFar ) {
- x = 2;
- }
- else if ( p.x > dFar + ( dUp - p.z ) * dUp * invFar ) {
- x = 2;
- }
- }
- r = sphere.GetRadius();
- index = VORONOI_INDEX( x, y, z );
- switch( index ) {
- case VORONOI_INDEX( 0, 0, 0 ): return true;
- case VORONOI_INDEX( 1, 0, 0 ): return ( dNear - p.x < r );
- case VORONOI_INDEX( 2, 0, 0 ): return ( p.x - dFar < r );
- case VORONOI_INDEX( 0, 1, 0 ): d = dFar * p.y - dLeft * p.x; return ( d * d < r * r * ( dFar * dFar + dLeft * dLeft ) );
- case VORONOI_INDEX( 0, 2, 0 ): d = -dFar * p.z - dLeft * p.x; return ( d * d < r * r * ( dFar * dFar + dLeft * dLeft ) );
- case VORONOI_INDEX( 0, 0, 1 ): d = dFar * p.z - dUp * p.x; return ( d * d < r * r * ( dFar * dFar + dUp * dUp ) );
- case VORONOI_INDEX( 0, 0, 2 ): d = -dFar * p.z - dUp * p.x; return ( d * d < r * r * ( dFar * dFar + dUp * dUp ) );
- default: {
- ToIndexPoints( points );
- switch( index ) {
- case VORONOI_INDEX( 1, 1, 1 ): return sphere.ContainsPoint( points[0] );
- case VORONOI_INDEX( 2, 1, 1 ): return sphere.ContainsPoint( points[4] );
- case VORONOI_INDEX( 1, 2, 1 ): return sphere.ContainsPoint( points[1] );
- case VORONOI_INDEX( 2, 2, 1 ): return sphere.ContainsPoint( points[5] );
- case VORONOI_INDEX( 1, 1, 2 ): return sphere.ContainsPoint( points[2] );
- case VORONOI_INDEX( 2, 1, 2 ): return sphere.ContainsPoint( points[6] );
- case VORONOI_INDEX( 1, 2, 2 ): return sphere.ContainsPoint( points[3] );
- case VORONOI_INDEX( 2, 2, 2 ): return sphere.ContainsPoint( points[7] );
- case VORONOI_INDEX( 1, 1, 0 ): return sphere.LineIntersection( points[0], points[2] );
- case VORONOI_INDEX( 2, 1, 0 ): return sphere.LineIntersection( points[4], points[6] );
- case VORONOI_INDEX( 1, 2, 0 ): return sphere.LineIntersection( points[1], points[3] );
- case VORONOI_INDEX( 2, 2, 0 ): return sphere.LineIntersection( points[5], points[7] );
- case VORONOI_INDEX( 1, 0, 1 ): return sphere.LineIntersection( points[0], points[1] );
- case VORONOI_INDEX( 2, 0, 1 ): return sphere.LineIntersection( points[4], points[5] );
- case VORONOI_INDEX( 0, 1, 1 ): return sphere.LineIntersection( points[0], points[4] );
- case VORONOI_INDEX( 0, 2, 1 ): return sphere.LineIntersection( points[1], points[5] );
- case VORONOI_INDEX( 1, 0, 2 ): return sphere.LineIntersection( points[2], points[3] );
- case VORONOI_INDEX( 2, 0, 2 ): return sphere.LineIntersection( points[6], points[7] );
- case VORONOI_INDEX( 0, 1, 2 ): return sphere.LineIntersection( points[2], points[6] );
- case VORONOI_INDEX( 0, 2, 2 ): return sphere.LineIntersection( points[3], points[7] );
- }
- break;
- }
- }
- return false;
- }
- /*
- ============
- idFrustum::IntersectsFrustum
- ============
- */
- bool idFrustum::IntersectsFrustum( const idFrustum &frustum ) const {
- idVec3 indexPoints2[8], cornerVecs2[4];
- idFrustum localFrustum2;
- localFrustum2 = frustum;
- localFrustum2.origin = ( frustum.origin - origin ) * axis.Transpose();
- localFrustum2.axis = frustum.axis * axis.Transpose();
- localFrustum2.ToIndexPointsAndCornerVecs( indexPoints2, cornerVecs2 );
- if ( CullLocalFrustum( localFrustum2, indexPoints2, cornerVecs2 ) ) {
- return false;
- }
- idVec3 indexPoints1[8], cornerVecs1[4];
- idFrustum localFrustum1;
- localFrustum1 = *this;
- localFrustum1.origin = ( origin - frustum.origin ) * frustum.axis.Transpose();
- localFrustum1.axis = axis * frustum.axis.Transpose();
- localFrustum1.ToIndexPointsAndCornerVecs( indexPoints1, cornerVecs1 );
- if ( frustum.CullLocalFrustum( localFrustum1, indexPoints1, cornerVecs1 ) ) {
- return false;
- }
- idSwap( indexPoints2[2], indexPoints2[3] );
- idSwap( indexPoints2[6], indexPoints2[7] );
- if ( LocalFrustumIntersectsFrustum( indexPoints2, ( localFrustum2.dNear > 0.0f ) ) ) {
- return true;
- }
- idSwap( indexPoints1[2], indexPoints1[3] );
- idSwap( indexPoints1[6], indexPoints1[7] );
- if ( frustum.LocalFrustumIntersectsFrustum( indexPoints1, ( localFrustum1.dNear > 0.0f ) ) ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::IntersectsWinding
- ============
- */
- bool idFrustum::IntersectsWinding( const idWinding &winding ) const {
- int i, j, *pointCull;
- float min, max;
- idVec3 *localPoints, indexPoints[8], cornerVecs[4];
- idMat3 transpose;
- idPlane plane;
- localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
- pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
- transpose = axis.Transpose();
- for ( i = 0; i < winding.GetNumPoints(); i++ ) {
- localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
- }
- // if the winding is culled
- if ( CullLocalWinding( localPoints, winding.GetNumPoints(), pointCull ) ) {
- return false;
- }
- winding.GetPlane( plane );
- ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- AxisProjection( indexPoints, cornerVecs, plane.Normal(), min, max );
- // if the frustum does not cross the winding plane
- if ( min + plane[3] > 0.0f || max + plane[3] < 0.0f ) {
- return false;
- }
- // test if any of the winding edges goes through the frustum
- for ( i = 0; i < winding.GetNumPoints(); i++ ) {
- j = (i+1)%winding.GetNumPoints();
- if ( !( pointCull[i] & pointCull[j] ) ) {
- if ( LocalLineIntersection( localPoints[i], localPoints[j] ) ) {
- return true;
- }
- }
- }
- idSwap( indexPoints[2], indexPoints[3] );
- idSwap( indexPoints[6], indexPoints[7] );
- // test if any edges of the frustum intersect the winding
- for ( i = 0; i < 4; i++ ) {
- if ( winding.LineIntersection( plane, indexPoints[i], indexPoints[4+i] ) ) {
- return true;
- }
- }
- if ( dNear > 0.0f ) {
- for ( i = 0; i < 4; i++ ) {
- if ( winding.LineIntersection( plane, indexPoints[i], indexPoints[(i+1)&3] ) ) {
- return true;
- }
- }
- }
- for ( i = 0; i < 4; i++ ) {
- if ( winding.LineIntersection( plane, indexPoints[4+i], indexPoints[4+((i+1)&3)] ) ) {
- return true;
- }
- }
- return false;
- }
- /*
- ============
- idFrustum::LineIntersection
- Returns true if the line intersects the box between the start and end point.
- ============
- */
- bool idFrustum::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
- return LocalLineIntersection( ( start - origin ) * axis.Transpose(), ( end - origin ) * axis.Transpose() );
- }
- /*
- ============
- idFrustum::RayIntersection
- Returns true if the ray intersects the bounds.
- The ray can intersect the bounds in both directions from the start point.
- If start is inside the frustum then scale1 < 0 and scale2 > 0.
- ============
- */
- bool idFrustum::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
- if ( LocalRayIntersection( ( start - origin ) * axis.Transpose(), dir * axis.Transpose(), scale1, scale2 ) ) {
- return true;
- }
- if ( scale1 <= scale2 ) {
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::FromProjection
- Creates a frustum which contains the projection of the bounds.
- ============
- */
- bool idFrustum::FromProjection( const idBounds &bounds, const idVec3 &projectionOrigin, const float dFar ) {
- return FromProjection( idBox( bounds, vec3_origin, mat3_identity ), projectionOrigin, dFar );
- }
- /*
- ============
- idFrustum::FromProjection
- Creates a frustum which contains the projection of the box.
- ============
- */
- bool idFrustum::FromProjection( const idBox &box, const idVec3 &projectionOrigin, const float dFar ) {
- int i, bestAxis;
- float value, bestValue;
- idVec3 dir;
- assert( dFar > 0.0f );
- this->dNear = this->dFar = this->invFar = 0.0f;
- dir = box.GetCenter() - projectionOrigin;
- if ( dir.Normalize() == 0.0f ) {
- return false;
- }
- bestAxis = 0;
- bestValue = idMath::Fabs( box.GetAxis()[0] * dir );
- for ( i = 1; i < 3; i++ ) {
- value = idMath::Fabs( box.GetAxis()[i] * dir );
- if ( value * box.GetExtents()[bestAxis] * box.GetExtents()[bestAxis] < bestValue * box.GetExtents()[i] * box.GetExtents()[i] ) {
- bestValue = value;
- bestAxis = i;
- }
- }
- #if 1
- int j, minX, minY, maxY, minZ, maxZ;
- idVec3 points[8];
- minX = minY = maxY = minZ = maxZ = 0;
- for ( j = 0; j < 2; j++ ) {
- axis[0] = dir;
- axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
- axis[1].Normalize();
- axis[2].Cross( axis[0], axis[1] );
- BoxToPoints( ( box.GetCenter() - projectionOrigin ) * axis.Transpose(), box.GetExtents(), box.GetAxis() * axis.Transpose(), points );
- if ( points[0].x <= 1.0f ) {
- return false;
- }
- minX = minY = maxY = minZ = maxZ = 0;
- for ( i = 1; i < 8; i++ ) {
- if ( points[i].x <= 1.0f ) {
- return false;
- }
- if ( points[i].x < points[minX].x ) {
- minX = i;
- }
- if ( points[minY].x * points[i].y < points[i].x * points[minY].y ) {
- minY = i;
- } else if ( points[maxY].x * points[i].y > points[i].x * points[maxY].y ) {
- maxY = i;
- }
- if ( points[minZ].x * points[i].z < points[i].x * points[minZ].z ) {
- minZ = i;
- } else if ( points[maxZ].x * points[i].z > points[i].x * points[maxZ].z ) {
- maxZ = i;
- }
- }
- if ( j == 0 ) {
- dir += idMath::Tan16( 0.5f * ( idMath::ATan16( points[minY].y, points[minY].x ) + idMath::ATan16( points[maxY].y, points[maxY].x ) ) ) * axis[1];
- dir += idMath::Tan16( 0.5f * ( idMath::ATan16( points[minZ].z, points[minZ].x ) + idMath::ATan16( points[maxZ].z, points[maxZ].x ) ) ) * axis[2];
- dir.Normalize();
- }
- }
- this->origin = projectionOrigin;
- this->dNear = points[minX].x;
- this->dFar = dFar;
- this->dLeft = Max( idMath::Fabs( points[minY].y / points[minY].x ), idMath::Fabs( points[maxY].y / points[maxY].x ) ) * dFar;
- this->dUp = Max( idMath::Fabs( points[minZ].z / points[minZ].x ), idMath::Fabs( points[maxZ].z / points[maxZ].x ) ) * dFar;
- this->invFar = 1.0f / dFar;
- #elif 1
- int j;
- float f, x;
- idBounds b;
- idVec3 points[8];
- for ( j = 0; j < 2; j++ ) {
- axis[0] = dir;
- axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
- axis[1].Normalize();
- axis[2].Cross( axis[0], axis[1] );
- BoxToPoints( ( box.GetCenter() - projectionOrigin ) * axis.Transpose(), box.GetExtents(), box.GetAxis() * axis.Transpose(), points );
- b.Clear();
- for ( i = 0; i < 8; i++ ) {
- x = points[i].x;
- if ( x <= 1.0f ) {
- return false;
- }
- f = 1.0f / x;
- points[i].y *= f;
- points[i].z *= f;
- b.AddPoint( points[i] );
- }
- if ( j == 0 ) {
- dir += idMath::Tan16( 0.5f * ( idMath::ATan16( b[1][1] ) + idMath::ATan16( b[0][1] ) ) ) * axis[1];
- dir += idMath::Tan16( 0.5f * ( idMath::ATan16( b[1][2] ) + idMath::ATan16( b[0][2] ) ) ) * axis[2];
- dir.Normalize();
- }
- }
- this->origin = projectionOrigin;
- this->dNear = b[0][0];
- this->dFar = dFar;
- this->dLeft = Max( idMath::Fabs( b[0][1] ), idMath::Fabs( b[1][1] ) ) * dFar;
- this->dUp = Max( idMath::Fabs( b[0][2] ), idMath::Fabs( b[1][2] ) ) * dFar;
- this->invFar = 1.0f / dFar;
- #else
- float dist;
- idVec3 org;
- axis[0] = dir;
- axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
- axis[1].Normalize();
- axis[2].Cross( axis[0], axis[1] );
- for ( i = 0; i < 3; i++ ) {
- dist[i] = idMath::Fabs( box.GetExtents()[0] * ( axis[i] * box.GetAxis()[0] ) ) +
- idMath::Fabs( box.GetExtents()[1] * ( axis[i] * box.GetAxis()[1] ) ) +
- idMath::Fabs( box.GetExtents()[2] * ( axis[i] * box.GetAxis()[2] ) );
- }
- dist[0] = axis[0] * ( box.GetCenter() - projectionOrigin ) - dist[0];
- if ( dist[0] <= 1.0f ) {
- return false;
- }
- float invDist = 1.0f / dist[0];
- this->origin = projectionOrigin;
- this->dNear = dist[0];
- this->dFar = dFar;
- this->dLeft = dist[1] * invDist * dFar;
- this->dUp = dist[2] * invDist * dFar;
- this->invFar = 1.0f / dFar;
- #endif
- return true;
- }
- /*
- ============
- idFrustum::FromProjection
- Creates a frustum which contains the projection of the sphere.
- ============
- */
- bool idFrustum::FromProjection( const idSphere &sphere, const idVec3 &projectionOrigin, const float dFar ) {
- idVec3 dir;
- float d, r, s, x, y;
- assert( dFar > 0.0f );
- dir = sphere.GetOrigin() - projectionOrigin;
- d = dir.Normalize();
- r = sphere.GetRadius();
- if ( d <= r + 1.0f ) {
- this->dNear = this->dFar = this->invFar = 0.0f;
- return false;
- }
- origin = projectionOrigin;
- axis = dir.ToMat3();
- s = idMath::Sqrt( d * d - r * r );
- x = r / d * s;
- y = idMath::Sqrt( s * s - x * x );
- this->dNear = d - r;
- this->dFar = dFar;
- this->dLeft = x / y * dFar;
- this->dUp = dLeft;
- this->invFar = 1.0f / dFar;
- return true;
- }
- /*
- ============
- idFrustum::ConstrainToBounds
- Returns false if no part of the bounds extends beyond the near plane.
- ============
- */
- bool idFrustum::ConstrainToBounds( const idBounds &bounds ) {
- float min, max, newdFar;
- bounds.AxisProjection( axis[0], min, max );
- newdFar = max - axis[0] * origin;
- if ( newdFar <= dNear ) {
- MoveFarDistance( dNear + 1.0f );
- return false;
- }
- MoveFarDistance( newdFar );
- return true;
- }
- /*
- ============
- idFrustum::ConstrainToBox
- Returns false if no part of the box extends beyond the near plane.
- ============
- */
- bool idFrustum::ConstrainToBox( const idBox &box ) {
- float min, max, newdFar;
- box.AxisProjection( axis[0], min, max );
- newdFar = max - axis[0] * origin;
- if ( newdFar <= dNear ) {
- MoveFarDistance( dNear + 1.0f );
- return false;
- }
- MoveFarDistance( newdFar );
- return true;
- }
- /*
- ============
- idFrustum::ConstrainToSphere
- Returns false if no part of the sphere extends beyond the near plane.
- ============
- */
- bool idFrustum::ConstrainToSphere( const idSphere &sphere ) {
- float min, max, newdFar;
- sphere.AxisProjection( axis[0], min, max );
- newdFar = max - axis[0] * origin;
- if ( newdFar <= dNear ) {
- MoveFarDistance( dNear + 1.0f );
- return false;
- }
- MoveFarDistance( newdFar );
- return true;
- }
- /*
- ============
- idFrustum::ConstrainToFrustum
- Returns false if no part of the frustum extends beyond the near plane.
- ============
- */
- bool idFrustum::ConstrainToFrustum( const idFrustum &frustum ) {
- float min, max, newdFar;
- frustum.AxisProjection( axis[0], min, max );
- newdFar = max - axis[0] * origin;
- if ( newdFar <= dNear ) {
- MoveFarDistance( dNear + 1.0f );
- return false;
- }
- MoveFarDistance( newdFar );
- return true;
- }
- /*
- ============
- idFrustum::ToPlanes
- planes point outwards
- ============
- */
- void idFrustum::ToPlanes( idPlane planes[6] ) const {
- int i;
- idVec3 scaled[2];
- idVec3 points[4];
- planes[0].Normal() = -axis[0];
- planes[0].SetDist( -dNear );
- planes[1].Normal() = axis[0];
- planes[1].SetDist( dFar );
- scaled[0] = axis[1] * dLeft;
- scaled[1] = axis[2] * dUp;
- points[0] = scaled[0] + scaled[1];
- points[1] = -scaled[0] + scaled[1];
- points[2] = -scaled[0] - scaled[1];
- points[3] = scaled[0] - scaled[1];
- for ( i = 0; i < 4; i++ ) {
- planes[i+2].Normal() = points[i].Cross( points[(i+1)&3] - points[i] );
- planes[i+2].Normalize();
- planes[i+2].FitThroughPoint( points[i] );
- }
- }
- /*
- ============
- idFrustum::ToPoints
- ============
- */
- void idFrustum::ToPoints( idVec3 points[8] ) const {
- idMat3 scaled;
- scaled[0] = origin + axis[0] * dNear;
- scaled[1] = axis[1] * ( dLeft * dNear * invFar );
- scaled[2] = axis[2] * ( dUp * dNear * invFar );
- points[0] = scaled[0] + scaled[1];
- points[1] = scaled[0] - scaled[1];
- points[2] = points[1] - scaled[2];
- points[3] = points[0] - scaled[2];
- points[0] += scaled[2];
- points[1] += scaled[2];
- scaled[0] = origin + axis[0] * dFar;
- scaled[1] = axis[1] * dLeft;
- scaled[2] = axis[2] * dUp;
- points[4] = scaled[0] + scaled[1];
- points[5] = scaled[0] - scaled[1];
- points[6] = points[5] - scaled[2];
- points[7] = points[4] - scaled[2];
- points[4] += scaled[2];
- points[5] += scaled[2];
- }
- /*
- ============
- idFrustum::ToClippedPoints
- ============
- */
- void idFrustum::ToClippedPoints( const float fractions[4], idVec3 points[8] ) const {
- idMat3 scaled;
- scaled[0] = origin + axis[0] * dNear;
- scaled[1] = axis[1] * ( dLeft * dNear * invFar );
- scaled[2] = axis[2] * ( dUp * dNear * invFar );
- points[0] = scaled[0] + scaled[1];
- points[1] = scaled[0] - scaled[1];
- points[2] = points[1] - scaled[2];
- points[3] = points[0] - scaled[2];
- points[0] += scaled[2];
- points[1] += scaled[2];
- scaled[0] = axis[0] * dFar;
- scaled[1] = axis[1] * dLeft;
- scaled[2] = axis[2] * dUp;
- points[4] = scaled[0] + scaled[1];
- points[5] = scaled[0] - scaled[1];
- points[6] = points[5] - scaled[2];
- points[7] = points[4] - scaled[2];
- points[4] += scaled[2];
- points[5] += scaled[2];
- points[4] = origin + fractions[0] * points[4];
- points[5] = origin + fractions[1] * points[5];
- points[6] = origin + fractions[2] * points[6];
- points[7] = origin + fractions[3] * points[7];
- }
- /*
- ============
- idFrustum::ToIndexPoints
- ============
- */
- void idFrustum::ToIndexPoints( idVec3 indexPoints[8] ) const {
- idMat3 scaled;
- scaled[0] = origin + axis[0] * dNear;
- scaled[1] = axis[1] * ( dLeft * dNear * invFar );
- scaled[2] = axis[2] * ( dUp * dNear * invFar );
- indexPoints[0] = scaled[0] - scaled[1];
- indexPoints[2] = scaled[0] + scaled[1];
- indexPoints[1] = indexPoints[0] + scaled[2];
- indexPoints[3] = indexPoints[2] + scaled[2];
- indexPoints[0] -= scaled[2];
- indexPoints[2] -= scaled[2];
- scaled[0] = origin + axis[0] * dFar;
- scaled[1] = axis[1] * dLeft;
- scaled[2] = axis[2] * dUp;
- indexPoints[4] = scaled[0] - scaled[1];
- indexPoints[6] = scaled[0] + scaled[1];
- indexPoints[5] = indexPoints[4] + scaled[2];
- indexPoints[7] = indexPoints[6] + scaled[2];
- indexPoints[4] -= scaled[2];
- indexPoints[6] -= scaled[2];
- }
- /*
- ============
- idFrustum::ToIndexPointsAndCornerVecs
- 22 muls
- ============
- */
- void idFrustum::ToIndexPointsAndCornerVecs( idVec3 indexPoints[8], idVec3 cornerVecs[4] ) const {
- idMat3 scaled;
- scaled[0] = origin + axis[0] * dNear;
- scaled[1] = axis[1] * ( dLeft * dNear * invFar );
- scaled[2] = axis[2] * ( dUp * dNear * invFar );
- indexPoints[0] = scaled[0] - scaled[1];
- indexPoints[2] = scaled[0] + scaled[1];
- indexPoints[1] = indexPoints[0] + scaled[2];
- indexPoints[3] = indexPoints[2] + scaled[2];
- indexPoints[0] -= scaled[2];
- indexPoints[2] -= scaled[2];
- scaled[0] = axis[0] * dFar;
- scaled[1] = axis[1] * dLeft;
- scaled[2] = axis[2] * dUp;
- cornerVecs[0] = scaled[0] - scaled[1];
- cornerVecs[2] = scaled[0] + scaled[1];
- cornerVecs[1] = cornerVecs[0] + scaled[2];
- cornerVecs[3] = cornerVecs[2] + scaled[2];
- cornerVecs[0] -= scaled[2];
- cornerVecs[2] -= scaled[2];
- indexPoints[4] = cornerVecs[0] + origin;
- indexPoints[5] = cornerVecs[1] + origin;
- indexPoints[6] = cornerVecs[2] + origin;
- indexPoints[7] = cornerVecs[3] + origin;
- }
- /*
- ============
- idFrustum::AxisProjection
- 18 muls
- ============
- */
- void idFrustum::AxisProjection( const idVec3 indexPoints[8], const idVec3 cornerVecs[4], const idVec3 &dir, float &min, float &max ) const {
- float dx, dy, dz;
- int index;
- dy = dir.x * axis[1].x + dir.y * axis[1].y + dir.z * axis[1].z;
- dz = dir.x * axis[2].x + dir.y * axis[2].y + dir.z * axis[2].z;
- index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
- dx = dir.x * cornerVecs[index].x + dir.y * cornerVecs[index].y + dir.z * cornerVecs[index].z;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- min = indexPoints[index] * dir;
- index = ~index & 3;
- dx = -dir.x * cornerVecs[index].x - dir.y * cornerVecs[index].y - dir.z * cornerVecs[index].z;
- index |= ( FLOATSIGNBITSET( dx ) << 2 );
- max = indexPoints[index] * dir;
- }
- /*
- ============
- idFrustum::AxisProjection
- 40 muls
- ============
- */
- void idFrustum::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
- idVec3 indexPoints[8], cornerVecs[4];
- ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- AxisProjection( indexPoints, cornerVecs, dir, min, max );
- }
- /*
- ============
- idFrustum::AxisProjection
- 76 muls
- ============
- */
- void idFrustum::AxisProjection( const idMat3 &ax, idBounds &bounds ) const {
- idVec3 indexPoints[8], cornerVecs[4];
- ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
- AxisProjection( indexPoints, cornerVecs, ax[0], bounds[0][0], bounds[1][0] );
- AxisProjection( indexPoints, cornerVecs, ax[1], bounds[0][1], bounds[1][1] );
- AxisProjection( indexPoints, cornerVecs, ax[2], bounds[0][2], bounds[1][2] );
- }
- /*
- ============
- idFrustum::AddLocalLineToProjectionBoundsSetCull
- ============
- */
- void idFrustum::AddLocalLineToProjectionBoundsSetCull( const idVec3 &start, const idVec3 &end, int &startCull, int &endCull, idBounds &bounds ) const {
- idVec3 dir, p;
- float d1, d2, fstart, fend, lstart, lend, f;
- float leftScale, upScale;
- int cull1, cull2;
- #ifdef FRUSTUM_DEBUG
- static idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
- if ( r_showInteractionScissors.GetInteger() > 1 ) {
- session->rw->DebugLine( colorGreen, origin + start * axis, origin + end * axis );
- }
- #endif
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- dir = end - start;
- fstart = dFar * start.y;
- fend = dFar * end.y;
- lstart = dLeft * start.x;
- lend = dLeft * end.x;
- // test left plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- cull1 = FLOATSIGNBITSET( d1 );
- cull2 = FLOATSIGNBITSET( d2 );
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.z = start.z + f * dir.z;
- if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
- p.y = 1.0f;
- p.z = p.z * dFar / ( p.x * dUp );
- bounds.AddPoint( p );
- }
- }
- }
- }
- // test right plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- cull1 |= FLOATSIGNBITSET( d1 ) << 1;
- cull2 |= FLOATSIGNBITSET( d2 ) << 1;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.z = start.z + f * dir.z;
- if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
- p.y = -1.0f;
- p.z = p.z * dFar / ( p.x * dUp );
- bounds.AddPoint( p );
- }
- }
- }
- }
- fstart = dFar * start.z;
- fend = dFar * end.z;
- lstart = dUp * start.x;
- lend = dUp * end.x;
- // test up plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- cull1 |= FLOATSIGNBITSET( d1 ) << 2;
- cull2 |= FLOATSIGNBITSET( d2 ) << 2;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.y = start.y + f * dir.y;
- if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
- p.y = p.y * dFar / ( p.x * dLeft );
- p.z = 1.0f;
- bounds.AddPoint( p );
- }
- }
- }
- }
- // test down plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- cull1 |= FLOATSIGNBITSET( d1 ) << 3;
- cull2 |= FLOATSIGNBITSET( d2 ) << 3;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.y = start.y + f * dir.y;
- if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
- p.y = p.y * dFar / ( p.x * dLeft );
- p.z = -1.0f;
- bounds.AddPoint( p );
- }
- }
- }
- }
- if ( cull1 == 0 && start.x > 0.0f ) {
- // add start point to projection bounds
- p.x = start.x;
- p.y = start.y * dFar / ( start.x * dLeft );
- p.z = start.z * dFar / ( start.x * dUp );
- bounds.AddPoint( p );
- }
- if ( cull2 == 0 && end.x > 0.0f ) {
- // add end point to projection bounds
- p.x = end.x;
- p.y = end.y * dFar / ( end.x * dLeft );
- p.z = end.z * dFar / ( end.x * dUp );
- bounds.AddPoint( p );
- }
- if ( start.x < bounds[0].x ) {
- bounds[0].x = start.x < 0.0f ? 0.0f : start.x;
- }
- if ( end.x < bounds[0].x ) {
- bounds[0].x = end.x < 0.0f ? 0.0f : end.x;
- }
- startCull = cull1;
- endCull = cull2;
- }
- /*
- ============
- idFrustum::AddLocalLineToProjectionBoundsUseCull
- ============
- */
- void idFrustum::AddLocalLineToProjectionBoundsUseCull( const idVec3 &start, const idVec3 &end, int startCull, int endCull, idBounds &bounds ) const {
- idVec3 dir, p;
- float d1, d2, fstart, fend, lstart, lend, f;
- float leftScale, upScale;
- int clip;
- clip = startCull ^ endCull;
- if ( !clip ) {
- return;
- }
- #ifdef FRUSTUM_DEBUG
- static idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
- if ( r_showInteractionScissors.GetInteger() > 1 ) {
- session->rw->DebugLine( colorGreen, origin + start * axis, origin + end * axis );
- }
- #endif
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- dir = end - start;
- if ( clip & (1|2) ) {
- fstart = dFar * start.y;
- fend = dFar * end.y;
- lstart = dLeft * start.x;
- lend = dLeft * end.x;
- if ( clip & 1 ) {
- // test left plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.z = start.z + f * dir.z;
- if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
- p.y = 1.0f;
- p.z = p.z * dFar / ( p.x * dUp );
- bounds.AddPoint( p );
- }
- }
- }
- }
- }
- if ( clip & 2 ) {
- // test right plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.z = start.z + f * dir.z;
- if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
- p.y = -1.0f;
- p.z = p.z * dFar / ( p.x * dUp );
- bounds.AddPoint( p );
- }
- }
- }
- }
- }
- }
- if ( clip & (4|8) ) {
- fstart = dFar * start.z;
- fend = dFar * end.z;
- lstart = dUp * start.x;
- lend = dUp * end.x;
- if ( clip & 4 ) {
- // test up plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.y = start.y + f * dir.y;
- if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
- p.y = p.y * dFar / ( p.x * dLeft );
- p.z = 1.0f;
- bounds.AddPoint( p );
- }
- }
- }
- }
- }
- if ( clip & 8 ) {
- // test down plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( p.x > 0.0f ) {
- p.y = start.y + f * dir.y;
- if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
- p.y = p.y * dFar / ( p.x * dLeft );
- p.z = -1.0f;
- bounds.AddPoint( p );
- }
- }
- }
- }
- }
- }
- }
- /*
- ============
- idFrustum::BoundsRayIntersection
- Returns true if the ray starts inside the bounds.
- If there was an intersection scale1 <= scale2
- ============
- */
- bool idFrustum::BoundsRayIntersection( const idBounds &bounds, const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
- idVec3 end, p;
- float d1, d2, f;
- int i, startInside = 1;
- scale1 = idMath::INFINITY;
- scale2 = -idMath::INFINITY;
- end = start + dir;
- for ( i = 0; i < 2; i++ ) {
- d1 = start.x - bounds[i].x;
- startInside &= FLOATSIGNBITSET( d1 ) ^ i;
- d2 = end.x - bounds[i].x;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- p.y = start.y + f * dir.y;
- if ( bounds[0].y <= p.y && p.y <= bounds[1].y ) {
- p.z = start.z + f * dir.z;
- if ( bounds[0].z <= p.z && p.z <= bounds[1].z ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- d1 = start.y - bounds[i].y;
- startInside &= FLOATSIGNBITSET( d1 ) ^ i;
- d2 = end.y - bounds[i].y;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( bounds[0].x <= p.x && p.x <= bounds[1].x ) {
- p.z = start.z + f * dir.z;
- if ( bounds[0].z <= p.z && p.z <= bounds[1].z ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- d1 = start.z - bounds[i].z;
- startInside &= FLOATSIGNBITSET( d1 ) ^ i;
- d2 = end.z - bounds[i].z;
- if ( d1 != d2 ) {
- f = d1 / ( d1 - d2 );
- p.x = start.x + f * dir.x;
- if ( bounds[0].x <= p.x && p.x <= bounds[1].x ) {
- p.y = start.y + f * dir.y;
- if ( bounds[0].y <= p.y && p.y <= bounds[1].y ) {
- if ( f < scale1 ) scale1 = f;
- if ( f > scale2 ) scale2 = f;
- }
- }
- }
- }
- return ( startInside != 0 );
- }
- /*
- ============
- idFrustum::ProjectionBounds
- ============
- */
- bool idFrustum::ProjectionBounds( const idBounds &bounds, idBounds &projectionBounds ) const {
- return ProjectionBounds( idBox( bounds, vec3_origin, mat3_identity ), projectionBounds );
- }
- #ifndef __linux__
- /*
- ============
- idFrustum::ProjectionBounds
- ============
- */
- bool idFrustum::ProjectionBounds( const idBox &box, idBounds &projectionBounds ) const {
- int i, p1, p2, pointCull[8], culled, outside;
- float scale1, scale2;
- idFrustum localFrustum;
- idVec3 points[8], localOrigin;
- idMat3 localAxis, localScaled;
- idBounds bounds( -box.GetExtents(), box.GetExtents() );
- // if the frustum origin is inside the bounds
- if ( bounds.ContainsPoint( ( origin - box.GetCenter() ) * box.GetAxis().Transpose() ) ) {
- // bounds that cover the whole frustum
- float boxMin, boxMax, base;
- base = origin * axis[0];
- box.AxisProjection( axis[0], boxMin, boxMax );
- projectionBounds[0].x = boxMin - base;
- projectionBounds[1].x = boxMax - base;
- projectionBounds[0].y = projectionBounds[0].z = -1.0f;
- projectionBounds[1].y = projectionBounds[1].z = 1.0f;
- return true;
- }
- projectionBounds.Clear();
- // transform the bounds into the space of this frustum
- localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
- localAxis = box.GetAxis() * axis.Transpose();
- BoxToPoints( localOrigin, box.GetExtents(), localAxis, points );
- // test outer four edges of the bounds
- culled = -1;
- outside = 0;
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = 4 + i;
- AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- culled &= pointCull[p1] & pointCull[p2];
- outside |= pointCull[p1] | pointCull[p2];
- }
- // if the bounds are completely outside this frustum
- if ( culled ) {
- return false;
- }
- // if the bounds are completely inside this frustum
- if ( !outside ) {
- return true;
- }
- // test the remaining edges of the bounds
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = (i+1)&3;
- AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- }
- for ( i = 0; i < 4; i++ ) {
- p1 = 4 + i;
- p2 = 4 + ((i+1)&3);
- AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- }
- // if the bounds extend beyond two or more boundaries of this frustum
- if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
- localOrigin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
- localScaled = axis * box.GetAxis().Transpose();
- localScaled[0] *= dFar;
- localScaled[1] *= dLeft;
- localScaled[2] *= dUp;
- // test the outer edges of this frustum for intersection with the bounds
- if ( (outside & 2) && (outside & 8) ) {
- BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
- }
- }
- if ( (outside & 2) && (outside & 4) ) {
- BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 8) ) {
- BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 2) ) {
- BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
- }
- }
- }
- return true;
- }
- #endif
- /*
- ============
- idFrustum::ProjectionBounds
- ============
- */
- bool idFrustum::ProjectionBounds( const idSphere &sphere, idBounds &projectionBounds ) const {
- float d, r, rs, sFar;
- idVec3 center;
- projectionBounds.Clear();
- center = ( sphere.GetOrigin() - origin ) * axis.Transpose();
- r = sphere.GetRadius();
- rs = r * r;
- sFar = dFar * dFar;
- // test left/right planes
- d = dFar * idMath::Fabs( center.y ) - dLeft * center.x;
- if ( ( d * d ) > rs * ( sFar + dLeft * dLeft ) ) {
- return false;
- }
- // test up/down planes
- d = dFar * idMath::Fabs( center.z ) - dUp * center.x;
- if ( ( d * d ) > rs * ( sFar + dUp * dUp ) ) {
- return false;
- }
- // bounds that cover the whole frustum
- projectionBounds[0].x = 0.0f;
- projectionBounds[1].x = dFar;
- projectionBounds[0].y = projectionBounds[0].z = -1.0f;
- projectionBounds[1].y = projectionBounds[1].z = 1.0f;
- return true;
- }
- /*
- ============
- idFrustum::ProjectionBounds
- ============
- */
- bool idFrustum::ProjectionBounds( const idFrustum &frustum, idBounds &projectionBounds ) const {
- int i, p1, p2, pointCull[8], culled, outside;
- float scale1, scale2;
- idFrustum localFrustum;
- idVec3 points[8], localOrigin;
- idMat3 localScaled;
- // if the frustum origin is inside the other frustum
- if ( frustum.ContainsPoint( origin ) ) {
- // bounds that cover the whole frustum
- float frustumMin, frustumMax, base;
- base = origin * axis[0];
- frustum.AxisProjection( axis[0], frustumMin, frustumMax );
- projectionBounds[0].x = frustumMin - base;
- projectionBounds[1].x = frustumMax - base;
- projectionBounds[0].y = projectionBounds[0].z = -1.0f;
- projectionBounds[1].y = projectionBounds[1].z = 1.0f;
- return true;
- }
- projectionBounds.Clear();
- // transform the given frustum into the space of this frustum
- localFrustum = frustum;
- localFrustum.origin = ( frustum.origin - origin ) * axis.Transpose();
- localFrustum.axis = frustum.axis * axis.Transpose();
- localFrustum.ToPoints( points );
- // test outer four edges of the other frustum
- culled = -1;
- outside = 0;
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = 4 + i;
- AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- culled &= pointCull[p1] & pointCull[p2];
- outside |= pointCull[p1] | pointCull[p2];
- }
- // if the other frustum is completely outside this frustum
- if ( culled ) {
- return false;
- }
- // if the other frustum is completely inside this frustum
- if ( !outside ) {
- return true;
- }
- // test the remaining edges of the other frustum
- if ( localFrustum.dNear > 0.0f ) {
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = (i+1)&3;
- AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- }
- }
- for ( i = 0; i < 4; i++ ) {
- p1 = 4 + i;
- p2 = 4 + ((i+1)&3);
- AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
- }
- // if the other frustum extends beyond two or more boundaries of this frustum
- if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
- localOrigin = ( origin - frustum.origin ) * frustum.axis.Transpose();
- localScaled = axis * frustum.axis.Transpose();
- localScaled[0] *= dFar;
- localScaled[1] *= dLeft;
- localScaled[2] *= dUp;
- // test the outer edges of this frustum for intersection with the other frustum
- if ( (outside & 2) && (outside & 8) ) {
- frustum.LocalRayIntersection( localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
- }
- }
- if ( (outside & 2) && (outside & 4) ) {
- frustum.LocalRayIntersection( localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 8) ) {
- frustum.LocalRayIntersection( localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 2) ) {
- frustum.LocalRayIntersection( localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
- if ( scale1 <= scale2 && scale1 >= 0.0f ) {
- projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
- }
- }
- }
- return true;
- }
- /*
- ============
- idFrustum::ProjectionBounds
- ============
- */
- bool idFrustum::ProjectionBounds( const idWinding &winding, idBounds &projectionBounds ) const {
- int i, p1, p2, *pointCull, culled, outside;
- float scale;
- idVec3 *localPoints;
- idMat3 transpose, scaled;
- idPlane plane;
- projectionBounds.Clear();
- // transform the winding points into the space of this frustum
- localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
- transpose = axis.Transpose();
- for ( i = 0; i < winding.GetNumPoints(); i++ ) {
- localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
- }
- // test the winding edges
- culled = -1;
- outside = 0;
- pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
- for ( i = 0; i < winding.GetNumPoints(); i += 2 ) {
- p1 = i;
- p2 = (i+1)%winding.GetNumPoints();
- AddLocalLineToProjectionBoundsSetCull( localPoints[p1], localPoints[p2], pointCull[p1], pointCull[p2], projectionBounds );
- culled &= pointCull[p1] & pointCull[p2];
- outside |= pointCull[p1] | pointCull[p2];
- }
- // if completely culled
- if ( culled ) {
- return false;
- }
- // if completely inside
- if ( !outside ) {
- return true;
- }
- // test remaining winding edges
- for ( i = 1; i < winding.GetNumPoints(); i += 2 ) {
- p1 = i;
- p2 = (i+1)%winding.GetNumPoints();
- AddLocalLineToProjectionBoundsUseCull( localPoints[p1], localPoints[p2], pointCull[p1], pointCull[p2], projectionBounds );
- }
- // if the winding extends beyond two or more boundaries of this frustum
- if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
- winding.GetPlane( plane );
- scaled[0] = axis[0] * dFar;
- scaled[1] = axis[1] * dLeft;
- scaled[2] = axis[2] * dUp;
- // test the outer edges of this frustum for intersection with the winding
- if ( (outside & 2) && (outside & 8) ) {
- if ( winding.RayIntersection( plane, origin, scaled[0] - scaled[1] - scaled[2], scale ) ) {
- projectionBounds.AddPoint( idVec3( scale * dFar, -1.0f, -1.0f ) );
- }
- }
- if ( (outside & 2) && (outside & 4) ) {
- if ( winding.RayIntersection( plane, origin, scaled[0] - scaled[1] + scaled[2], scale ) ) {
- projectionBounds.AddPoint( idVec3( scale * dFar, -1.0f, 1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 8) ) {
- if ( winding.RayIntersection( plane, origin, scaled[0] + scaled[1] - scaled[2], scale ) ) {
- projectionBounds.AddPoint( idVec3( scale * dFar, 1.0f, -1.0f ) );
- }
- }
- if ( (outside & 1) && (outside & 2) ) {
- if ( winding.RayIntersection( plane, origin, scaled[0] + scaled[1] + scaled[2], scale ) ) {
- projectionBounds.AddPoint( idVec3( scale * dFar, 1.0f, 1.0f ) );
- }
- }
- }
- return true;
- }
- /*
- ============
- idFrustum::ClipFrustumToBox
- Clips the frustum far extents to the box.
- ============
- */
- void idFrustum::ClipFrustumToBox( const idBox &box, float clipFractions[4], int clipPlanes[4] ) const {
- int i, index;
- float f, minf;
- idMat3 scaled, localAxis, transpose;
- idVec3 localOrigin, cornerVecs[4];
- idBounds bounds;
- transpose = box.GetAxis();
- transpose.TransposeSelf();
- localOrigin = ( origin - box.GetCenter() ) * transpose;
- localAxis = axis * transpose;
- scaled[0] = localAxis[0] * dFar;
- scaled[1] = localAxis[1] * dLeft;
- scaled[2] = localAxis[2] * dUp;
- cornerVecs[0] = scaled[0] + scaled[1];
- cornerVecs[1] = scaled[0] - scaled[1];
- cornerVecs[2] = cornerVecs[1] - scaled[2];
- cornerVecs[3] = cornerVecs[0] - scaled[2];
- cornerVecs[0] += scaled[2];
- cornerVecs[1] += scaled[2];
- bounds[0] = -box.GetExtents();
- bounds[1] = box.GetExtents();
- minf = ( dNear + 1.0f ) * invFar;
- for ( i = 0; i < 4; i++ ) {
- index = FLOATSIGNBITNOTSET( cornerVecs[i].x );
- f = ( bounds[index].x - localOrigin.x ) / cornerVecs[i].x;
- clipFractions[i] = f;
- clipPlanes[i] = 1 << index;
- index = FLOATSIGNBITNOTSET( cornerVecs[i].y );
- f = ( bounds[index].y - localOrigin.y ) / cornerVecs[i].y;
- if ( f < clipFractions[i] ) {
- clipFractions[i] = f;
- clipPlanes[i] = 4 << index;
- }
- index = FLOATSIGNBITNOTSET( cornerVecs[i].z );
- f = ( bounds[index].z - localOrigin.z ) / cornerVecs[i].z;
- if ( f < clipFractions[i] ) {
- clipFractions[i] = f;
- clipPlanes[i] = 16 << index;
- }
- // make sure the frustum is not clipped between the frustum origin and the near plane
- if ( clipFractions[i] < minf ) {
- clipFractions[i] = minf;
- }
- }
- }
- /*
- ============
- idFrustum::ClipLine
- Returns true if part of the line is inside the frustum.
- Does not clip to the near and far plane.
- ============
- */
- bool idFrustum::ClipLine( const idVec3 localPoints[8], const idVec3 points[8], int startIndex, int endIndex, idVec3 &start, idVec3 &end, int &startClip, int &endClip ) const {
- float d1, d2, fstart, fend, lstart, lend, f, x;
- float leftScale, upScale;
- float scale1, scale2;
- int startCull, endCull;
- idVec3 localStart, localEnd, localDir;
- leftScale = dLeft * invFar;
- upScale = dUp * invFar;
- localStart = localPoints[startIndex];
- localEnd = localPoints[endIndex];
- localDir = localEnd - localStart;
- startClip = endClip = -1;
- scale1 = idMath::INFINITY;
- scale2 = -idMath::INFINITY;
- fstart = dFar * localStart.y;
- fend = dFar * localEnd.y;
- lstart = dLeft * localStart.x;
- lend = dLeft * localEnd.x;
- // test left plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- startCull = FLOATSIGNBITSET( d1 );
- endCull = FLOATSIGNBITSET( d2 );
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = localStart.x + f * localDir.x;
- if ( x >= 0.0f ) {
- if ( idMath::Fabs( localStart.z + f * localDir.z ) <= x * upScale ) {
- if ( f < scale1 ) { scale1 = f; startClip = 0; }
- if ( f > scale2 ) { scale2 = f; endClip = 0; }
- }
- }
- }
- }
- // test right plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- startCull |= FLOATSIGNBITSET( d1 ) << 1;
- endCull |= FLOATSIGNBITSET( d2 ) << 1;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = localStart.x + f * localDir.x;
- if ( x >= 0.0f ) {
- if ( idMath::Fabs( localStart.z + f * localDir.z ) <= x * upScale ) {
- if ( f < scale1 ) { scale1 = f; startClip = 1; }
- if ( f > scale2 ) { scale2 = f; endClip = 1; }
- }
- }
- }
- }
- fstart = dFar * localStart.z;
- fend = dFar * localEnd.z;
- lstart = dUp * localStart.x;
- lend = dUp * localEnd.x;
- // test up plane
- d1 = -fstart + lstart;
- d2 = -fend + lend;
- startCull |= FLOATSIGNBITSET( d1 ) << 2;
- endCull |= FLOATSIGNBITSET( d2 ) << 2;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = localStart.x + f * localDir.x;
- if ( x >= 0.0f ) {
- if ( idMath::Fabs( localStart.y + f * localDir.y ) <= x * leftScale ) {
- if ( f < scale1 ) { scale1 = f; startClip = 2; }
- if ( f > scale2 ) { scale2 = f; endClip = 2; }
- }
- }
- }
- }
- // test down plane
- d1 = fstart + lstart;
- d2 = fend + lend;
- startCull |= FLOATSIGNBITSET( d1 ) << 3;
- endCull |= FLOATSIGNBITSET( d2 ) << 3;
- if ( FLOATNOTZERO( d1 ) ) {
- if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
- f = d1 / ( d1 - d2 );
- x = localStart.x + f * localDir.x;
- if ( x >= 0.0f ) {
- if ( idMath::Fabs( localStart.y + f * localDir.y ) <= x * leftScale ) {
- if ( f < scale1 ) { scale1 = f; startClip = 3; }
- if ( f > scale2 ) { scale2 = f; endClip = 3; }
- }
- }
- }
- }
- // if completely inside
- if ( !( startCull | endCull ) ) {
- start = points[startIndex];
- end = points[endIndex];
- return true;
- }
- else if ( scale1 <= scale2 ) {
- if ( !startCull ) {
- start = points[startIndex];
- startClip = -1;
- }
- else {
- start = points[startIndex] + scale1 * ( points[endIndex] - points[startIndex] );
- }
- if ( !endCull ) {
- end = points[endIndex];
- endClip = -1;
- }
- else {
- end = points[startIndex] + scale2 * ( points[endIndex] - points[startIndex] );
- }
- return true;
- }
- return false;
- }
- /*
- ============
- idFrustum::AddLocalCapsToProjectionBounds
- ============
- */
- static int capPointIndex[4][2] = {
- { 0, 3 },
- { 1, 2 },
- { 0, 1 },
- { 2, 3 }
- };
- ID_INLINE bool idFrustum::AddLocalCapsToProjectionBounds( const idVec3 endPoints[4], const int endPointCull[4], const idVec3 &point, int pointCull, int pointClip, idBounds &projectionBounds ) const {
- int *p;
- if ( pointClip < 0 ) {
- return false;
- }
- p = capPointIndex[pointClip];
- AddLocalLineToProjectionBoundsUseCull( endPoints[p[0]], point, endPointCull[p[0]], pointCull, projectionBounds );
- AddLocalLineToProjectionBoundsUseCull( endPoints[p[1]], point, endPointCull[p[1]], pointCull, projectionBounds );
- return true;
- }
- /*
- ============
- idFrustum::ClippedProjectionBounds
- ============
- */
- bool idFrustum::ClippedProjectionBounds( const idFrustum &frustum, const idBox &clipBox, idBounds &projectionBounds ) const {
- int i, p1, p2, clipPointCull[8], clipPlanes[4], usedClipPlanes, nearCull, farCull, outside;
- int pointCull[2], startClip, endClip, boxPointCull[8];
- float clipFractions[4], s1, s2, t1, t2, leftScale, upScale;
- idFrustum localFrustum;
- idVec3 clipPoints[8], localPoints1[8], localPoints2[8], localOrigin1, localOrigin2, start, end;
- idMat3 localAxis1, localAxis2, transpose;
- idBounds clipBounds;
- // if the frustum origin is inside the other frustum
- if ( frustum.ContainsPoint( origin ) ) {
- // bounds that cover the whole frustum
- float clipBoxMin, clipBoxMax, frustumMin, frustumMax, base;
- base = origin * axis[0];
- clipBox.AxisProjection( axis[0], clipBoxMin, clipBoxMax );
- frustum.AxisProjection( axis[0], frustumMin, frustumMax );
- projectionBounds[0].x = Max( clipBoxMin, frustumMin ) - base;
- projectionBounds[1].x = Min( clipBoxMax, frustumMax ) - base;
- projectionBounds[0].y = projectionBounds[0].z = -1.0f;
- projectionBounds[1].y = projectionBounds[1].z = 1.0f;
- return true;
- }
- projectionBounds.Clear();
- // clip the outer edges of the given frustum to the clip bounds
- frustum.ClipFrustumToBox( clipBox, clipFractions, clipPlanes );
- usedClipPlanes = clipPlanes[0] | clipPlanes[1] | clipPlanes[2] | clipPlanes[3];
- // transform the clipped frustum to the space of this frustum
- transpose = axis;
- transpose.TransposeSelf();
- localFrustum = frustum;
- localFrustum.origin = ( frustum.origin - origin ) * transpose;
- localFrustum.axis = frustum.axis * transpose;
- localFrustum.ToClippedPoints( clipFractions, clipPoints );
- // test outer four edges of the clipped frustum
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = 4 + i;
- AddLocalLineToProjectionBoundsSetCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
- }
- // get cull bits for the clipped frustum
- outside = clipPointCull[0] | clipPointCull[1] | clipPointCull[2] | clipPointCull[3] |
- clipPointCull[4] | clipPointCull[5] | clipPointCull[6] | clipPointCull[7];
- nearCull = clipPointCull[0] & clipPointCull[1] & clipPointCull[2] & clipPointCull[3];
- farCull = clipPointCull[4] & clipPointCull[5] & clipPointCull[6] & clipPointCull[7];
- // if the clipped frustum is not completely inside this frustum
- if ( outside ) {
- // test the remaining edges of the clipped frustum
- if ( !nearCull && localFrustum.dNear > 0.0f ) {
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = (i+1)&3;
- AddLocalLineToProjectionBoundsUseCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
- }
- }
- if ( !farCull ) {
- for ( i = 0; i < 4; i++ ) {
- p1 = 4 + i;
- p2 = 4 + ((i+1)&3);
- AddLocalLineToProjectionBoundsUseCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
- }
- }
- }
- // if the clipped frustum far end points are inside this frustum
- if ( !( farCull && !( nearCull & farCull ) ) &&
- // if the clipped frustum is not clipped to a single plane of the clip bounds
- ( clipPlanes[0] != clipPlanes[1] || clipPlanes[1] != clipPlanes[2] || clipPlanes[2] != clipPlanes[3] ) ) {
- // transform the clip box into the space of the other frustum
- transpose = frustum.axis;
- transpose.TransposeSelf();
- localOrigin1 = ( clipBox.GetCenter() - frustum.origin ) * transpose;
- localAxis1 = clipBox.GetAxis() * transpose;
- BoxToPoints( localOrigin1, clipBox.GetExtents(), localAxis1, localPoints1 );
- // cull the box corners with the other frustum
- leftScale = frustum.dLeft * frustum.invFar;
- upScale = frustum.dUp * frustum.invFar;
- for ( i = 0; i < 8; i++ ) {
- idVec3 &p = localPoints1[i];
- if ( !( boxVertPlanes[i] & usedClipPlanes ) || p.x <= 0.0f ) {
- boxPointCull[i] = 1|2|4|8;
- }
- else {
- boxPointCull[i] = 0;
- if ( idMath::Fabs( p.y ) > p.x * leftScale ) {
- boxPointCull[i] |= 1 << FLOATSIGNBITSET( p.y );
- }
- if ( idMath::Fabs( p.z ) > p.x * upScale ) {
- boxPointCull[i] |= 4 << FLOATSIGNBITSET( p.z );
- }
- }
- }
- // transform the clip box into the space of this frustum
- transpose = axis;
- transpose.TransposeSelf();
- localOrigin2 = ( clipBox.GetCenter() - origin ) * transpose;
- localAxis2 = clipBox.GetAxis() * transpose;
- BoxToPoints( localOrigin2, clipBox.GetExtents(), localAxis2, localPoints2 );
- // clip the edges of the clip bounds to the other frustum and add the clipped edges to the projection bounds
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = 4 + i;
- if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
- if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
- AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
- outside |= pointCull[0] | pointCull[1];
- }
- }
- }
- for ( i = 0; i < 4; i++ ) {
- p1 = i;
- p2 = (i+1)&3;
- if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
- if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
- AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
- outside |= pointCull[0] | pointCull[1];
- }
- }
- }
- for ( i = 0; i < 4; i++ ) {
- p1 = 4 + i;
- p2 = 4 + ((i+1)&3);
- if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
- if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
- AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
- AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
- outside |= pointCull[0] | pointCull[1];
- }
- }
- }
- }
- // if the clipped frustum extends beyond two or more boundaries of this frustum
- if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
- // transform this frustum into the space of the other frustum
- transpose = frustum.axis;
- transpose.TransposeSelf();
- localOrigin1 = ( origin - frustum.origin ) * transpose;
- localAxis1 = axis * transpose;
- localAxis1[0] *= dFar;
- localAxis1[1] *= dLeft;
- localAxis1[2] *= dUp;
- // transform this frustum into the space of the clip bounds
- transpose = clipBox.GetAxis();
- transpose.TransposeSelf();
- localOrigin2 = ( origin - clipBox.GetCenter() ) * transpose;
- localAxis2 = axis * transpose;
- localAxis2[0] *= dFar;
- localAxis2[1] *= dLeft;
- localAxis2[2] *= dUp;
- clipBounds[0] = -clipBox.GetExtents();
- clipBounds[1] = clipBox.GetExtents();
- // test the outer edges of this frustum for intersection with both the other frustum and the clip bounds
- if ( (outside & 2) && (outside & 8) ) {
- frustum.LocalRayIntersection( localOrigin1, localAxis1[0] - localAxis1[1] - localAxis1[2], s1, s2 );
- if ( s1 <= s2 && s1 >= 0.0f ) {
- BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] - localAxis2[1] - localAxis2[2], t1, t2 );
- if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
- projectionBounds.AddPoint( idVec3( s1 * dFar, -1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( s2 * dFar, -1.0f, -1.0f ) );
- }
- }
- }
- if ( (outside & 2) && (outside & 4) ) {
- frustum.LocalRayIntersection( localOrigin1, localAxis1[0] - localAxis1[1] + localAxis1[2], s1, s2 );
- if ( s1 <= s2 && s1 >= 0.0f ) {
- BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] - localAxis2[1] + localAxis2[2], t1, t2 );
- if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
- projectionBounds.AddPoint( idVec3( s1 * dFar, -1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( s2 * dFar, -1.0f, 1.0f ) );
- }
- }
- }
- if ( (outside & 1) && (outside & 8) ) {
- frustum.LocalRayIntersection( localOrigin1, localAxis1[0] + localAxis1[1] - localAxis1[2], s1, s2 );
- if ( s1 <= s2 && s1 >= 0.0f ) {
- BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] + localAxis2[1] - localAxis2[2], t1, t2 );
- if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
- projectionBounds.AddPoint( idVec3( s1 * dFar, 1.0f, -1.0f ) );
- projectionBounds.AddPoint( idVec3( s2 * dFar, 1.0f, -1.0f ) );
- }
- }
- }
- if ( (outside & 1) && (outside & 2) ) {
- frustum.LocalRayIntersection( localOrigin1, localAxis1[0] + localAxis1[1] + localAxis1[2], s1, s2 );
- if ( s1 <= s2 && s1 >= 0.0f ) {
- BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] + localAxis2[1] + localAxis2[2], t1, t2 );
- if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
- projectionBounds.AddPoint( idVec3( s1 * dFar, 1.0f, 1.0f ) );
- projectionBounds.AddPoint( idVec3( s2 * dFar, 1.0f, 1.0f ) );
- }
- }
- }
- }
- return true;
- }
|