Frustum.cpp 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../precompiled.h"
  21. #pragma hdrstop
  22. //#define FRUSTUM_DEBUG
  23. /*
  24. bit 0 = min x
  25. bit 1 = max x
  26. bit 2 = min y
  27. bit 3 = max y
  28. bit 4 = min z
  29. bit 5 = max z
  30. */
  31. static int boxVertPlanes[8] = {
  32. ( (1<<0) | (1<<2) | (1<<4) ),
  33. ( (1<<1) | (1<<2) | (1<<4) ),
  34. ( (1<<1) | (1<<3) | (1<<4) ),
  35. ( (1<<0) | (1<<3) | (1<<4) ),
  36. ( (1<<0) | (1<<2) | (1<<5) ),
  37. ( (1<<1) | (1<<2) | (1<<5) ),
  38. ( (1<<1) | (1<<3) | (1<<5) ),
  39. ( (1<<0) | (1<<3) | (1<<5) ),
  40. };
  41. /*
  42. ============
  43. BoxToPoints
  44. ============
  45. */
  46. void BoxToPoints( const idVec3 &center, const idVec3 &extents, const idMat3 &axis, idVec3 points[8] ) {
  47. idMat3 ax;
  48. idVec3 temp[4];
  49. ax[0] = extents[0] * axis[0];
  50. ax[1] = extents[1] * axis[1];
  51. ax[2] = extents[2] * axis[2];
  52. temp[0] = center - ax[0];
  53. temp[1] = center + ax[0];
  54. temp[2] = ax[1] - ax[2];
  55. temp[3] = ax[1] + ax[2];
  56. points[0] = temp[0] - temp[3];
  57. points[1] = temp[1] - temp[3];
  58. points[2] = temp[1] + temp[2];
  59. points[3] = temp[0] + temp[2];
  60. points[4] = temp[0] - temp[2];
  61. points[5] = temp[1] - temp[2];
  62. points[6] = temp[1] + temp[3];
  63. points[7] = temp[0] + temp[3];
  64. }
  65. /*
  66. ================
  67. idFrustum::PlaneDistance
  68. ================
  69. */
  70. float idFrustum::PlaneDistance( const idPlane &plane ) const {
  71. float min, max;
  72. AxisProjection( plane.Normal(), min, max );
  73. if ( min + plane[3] > 0.0f ) {
  74. return min + plane[3];
  75. }
  76. if ( max + plane[3] < 0.0f ) {
  77. return max + plane[3];
  78. }
  79. return 0.0f;
  80. }
  81. /*
  82. ================
  83. idFrustum::PlaneSide
  84. ================
  85. */
  86. int idFrustum::PlaneSide( const idPlane &plane, const float epsilon ) const {
  87. float min, max;
  88. AxisProjection( plane.Normal(), min, max );
  89. if ( min + plane[3] > epsilon ) {
  90. return PLANESIDE_FRONT;
  91. }
  92. if ( max + plane[3] < epsilon ) {
  93. return PLANESIDE_BACK;
  94. }
  95. return PLANESIDE_CROSS;
  96. }
  97. /*
  98. ============
  99. idFrustum::CullPoint
  100. ============
  101. */
  102. bool idFrustum::CullPoint( const idVec3 &point ) const {
  103. idVec3 p;
  104. float scale;
  105. // transform point to frustum space
  106. p = ( point - origin ) * axis.Transpose();
  107. // test whether or not the point is within the frustum
  108. if ( p.x < dNear || p.x > dFar ) {
  109. return true;
  110. }
  111. scale = p.x * invFar;
  112. if ( idMath::Fabs( p.y ) > dLeft * scale ) {
  113. return true;
  114. }
  115. if ( idMath::Fabs( p.z ) > dUp * scale ) {
  116. return true;
  117. }
  118. return false;
  119. }
  120. /*
  121. ============
  122. idFrustum::CullLocalBox
  123. Tests if any of the planes of the frustum can be used as a separating plane.
  124. 3 muls best case
  125. 25 muls worst case
  126. ============
  127. */
  128. bool idFrustum::CullLocalBox( const idVec3 &localOrigin, const idVec3 &extents, const idMat3 &localAxis ) const {
  129. float d1, d2;
  130. idVec3 testOrigin;
  131. idMat3 testAxis;
  132. // near plane
  133. d1 = dNear - localOrigin.x;
  134. d2 = idMath::Fabs( extents[0] * localAxis[0][0] ) +
  135. idMath::Fabs( extents[1] * localAxis[1][0] ) +
  136. idMath::Fabs( extents[2] * localAxis[2][0] );
  137. if ( d1 - d2 > 0.0f ) {
  138. return true;
  139. }
  140. // far plane
  141. d1 = localOrigin.x - dFar;
  142. if ( d1 - d2 > 0.0f ) {
  143. return true;
  144. }
  145. testOrigin = localOrigin;
  146. testAxis = localAxis;
  147. if ( testOrigin.y < 0.0f ) {
  148. testOrigin.y = -testOrigin.y;
  149. testAxis[0][1] = -testAxis[0][1];
  150. testAxis[1][1] = -testAxis[1][1];
  151. testAxis[2][1] = -testAxis[2][1];
  152. }
  153. // test left/right planes
  154. d1 = dFar * testOrigin.y - dLeft * testOrigin.x;
  155. d2 = idMath::Fabs( extents[0] * ( dFar * testAxis[0][1] - dLeft * testAxis[0][0] ) ) +
  156. idMath::Fabs( extents[1] * ( dFar * testAxis[1][1] - dLeft * testAxis[1][0] ) ) +
  157. idMath::Fabs( extents[2] * ( dFar * testAxis[2][1] - dLeft * testAxis[2][0] ) );
  158. if ( d1 - d2 > 0.0f ) {
  159. return true;
  160. }
  161. if ( testOrigin.z < 0.0f ) {
  162. testOrigin.z = -testOrigin.z;
  163. testAxis[0][2] = -testAxis[0][2];
  164. testAxis[1][2] = -testAxis[1][2];
  165. testAxis[2][2] = -testAxis[2][2];
  166. }
  167. // test up/down planes
  168. d1 = dFar * testOrigin.z - dUp * testOrigin.x;
  169. d2 = idMath::Fabs( extents[0] * ( dFar * testAxis[0][2] - dUp * testAxis[0][0] ) ) +
  170. idMath::Fabs( extents[1] * ( dFar * testAxis[1][2] - dUp * testAxis[1][0] ) ) +
  171. idMath::Fabs( extents[2] * ( dFar * testAxis[2][2] - dUp * testAxis[2][0] ) );
  172. if ( d1 - d2 > 0.0f ) {
  173. return true;
  174. }
  175. return false;
  176. }
  177. /*
  178. ============
  179. idFrustum::CullBounds
  180. Tests if any of the planes of the frustum can be used as a separating plane.
  181. 24 muls best case
  182. 37 muls worst case
  183. ============
  184. */
  185. bool idFrustum::CullBounds( const idBounds &bounds ) const {
  186. idVec3 localOrigin, center, extents;
  187. idMat3 localAxis;
  188. center = ( bounds[0] + bounds[1] ) * 0.5f;
  189. extents = bounds[1] - center;
  190. // transform the bounds into the space of this frustum
  191. localOrigin = ( center - origin ) * axis.Transpose();
  192. localAxis = axis.Transpose();
  193. return CullLocalBox( localOrigin, extents, localAxis );
  194. }
  195. /*
  196. ============
  197. idFrustum::CullBounds
  198. Tests if any of the planes of the frustum can be used as a separating plane.
  199. 39 muls best case
  200. 61 muls worst case
  201. ============
  202. */
  203. bool idFrustum::CullBox( const idBox &box ) const {
  204. idVec3 localOrigin;
  205. idMat3 localAxis;
  206. // transform the box into the space of this frustum
  207. localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
  208. localAxis = box.GetAxis() * axis.Transpose();
  209. return CullLocalBox( localOrigin, box.GetExtents(), localAxis );
  210. }
  211. /*
  212. ============
  213. idFrustum::CullSphere
  214. Tests if any of the planes of the frustum can be used as a separating plane.
  215. 9 muls best case
  216. 21 muls worst case
  217. ============
  218. */
  219. bool idFrustum::CullSphere( const idSphere &sphere ) const {
  220. float d, r, rs, sFar;
  221. idVec3 center;
  222. center = ( sphere.GetOrigin() - origin ) * axis.Transpose();
  223. r = sphere.GetRadius();
  224. // test near plane
  225. if ( dNear - center.x > r ) {
  226. return true;
  227. }
  228. // test far plane
  229. if ( center.x - dFar > r ) {
  230. return true;
  231. }
  232. rs = r * r;
  233. sFar = dFar * dFar;
  234. // test left/right planes
  235. d = dFar * idMath::Fabs( center.y ) - dLeft * center.x;
  236. if ( ( d * d ) > rs * ( sFar + dLeft * dLeft ) ) {
  237. return true;
  238. }
  239. // test up/down planes
  240. d = dFar * idMath::Fabs( center.z ) - dUp * center.x;
  241. if ( ( d * d ) > rs * ( sFar + dUp * dUp ) ) {
  242. return true;
  243. }
  244. return false;
  245. }
  246. /*
  247. ============
  248. idFrustum::CullLocalFrustum
  249. Tests if any of the planes of this frustum can be used as a separating plane.
  250. 0 muls best case
  251. 30 muls worst case
  252. ============
  253. */
  254. bool idFrustum::CullLocalFrustum( const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const {
  255. int index;
  256. float dx, dy, dz, leftScale, upScale;
  257. // test near plane
  258. dy = -localFrustum.axis[1].x;
  259. dz = -localFrustum.axis[2].x;
  260. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  261. dx = -cornerVecs[index].x;
  262. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  263. if ( indexPoints[index].x < dNear ) {
  264. return true;
  265. }
  266. // test far plane
  267. dy = localFrustum.axis[1].x;
  268. dz = localFrustum.axis[2].x;
  269. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  270. dx = cornerVecs[index].x;
  271. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  272. if ( indexPoints[index].x > dFar ) {
  273. return true;
  274. }
  275. leftScale = dLeft * invFar;
  276. // test left plane
  277. dy = dFar * localFrustum.axis[1].y - dLeft * localFrustum.axis[1].x;
  278. dz = dFar * localFrustum.axis[2].y - dLeft * localFrustum.axis[2].x;
  279. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  280. dx = dFar * cornerVecs[index].y - dLeft * cornerVecs[index].x;
  281. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  282. if ( indexPoints[index].y > indexPoints[index].x * leftScale ) {
  283. return true;
  284. }
  285. // test right plane
  286. dy = -dFar * localFrustum.axis[1].y - dLeft * localFrustum.axis[1].x;
  287. dz = -dFar * localFrustum.axis[2].y - dLeft * localFrustum.axis[2].x;
  288. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  289. dx = -dFar * cornerVecs[index].y - dLeft * cornerVecs[index].x;
  290. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  291. if ( indexPoints[index].y < -indexPoints[index].x * leftScale ) {
  292. return true;
  293. }
  294. upScale = dUp * invFar;
  295. // test up plane
  296. dy = dFar * localFrustum.axis[1].z - dUp * localFrustum.axis[1].x;
  297. dz = dFar * localFrustum.axis[2].z - dUp * localFrustum.axis[2].x;
  298. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  299. dx = dFar * cornerVecs[index].z - dUp * cornerVecs[index].x;
  300. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  301. if ( indexPoints[index].z > indexPoints[index].x * upScale ) {
  302. return true;
  303. }
  304. // test down plane
  305. dy = -dFar * localFrustum.axis[1].z - dUp * localFrustum.axis[1].x;
  306. dz = -dFar * localFrustum.axis[2].z - dUp * localFrustum.axis[2].x;
  307. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  308. dx = -dFar * cornerVecs[index].z - dUp * cornerVecs[index].x;
  309. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  310. if ( indexPoints[index].z < -indexPoints[index].x * upScale ) {
  311. return true;
  312. }
  313. return false;
  314. }
  315. /*
  316. ============
  317. idFrustum::CullFrustum
  318. Tests if any of the planes of this frustum can be used as a separating plane.
  319. 58 muls best case
  320. 88 muls worst case
  321. ============
  322. */
  323. bool idFrustum::CullFrustum( const idFrustum &frustum ) const {
  324. idFrustum localFrustum;
  325. idVec3 indexPoints[8], cornerVecs[4];
  326. // transform the given frustum into the space of this frustum
  327. localFrustum = frustum;
  328. localFrustum.origin = ( frustum.origin - origin ) * axis.Transpose();
  329. localFrustum.axis = frustum.axis * axis.Transpose();
  330. localFrustum.ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  331. return CullLocalFrustum( localFrustum, indexPoints, cornerVecs );
  332. }
  333. /*
  334. ============
  335. idFrustum::CullLocalWinding
  336. ============
  337. */
  338. bool idFrustum::CullLocalWinding( const idVec3 *points, const int numPoints, int *pointCull ) const {
  339. int i, pCull, culled;
  340. float leftScale, upScale;
  341. leftScale = dLeft * invFar;
  342. upScale = dUp * invFar;
  343. culled = -1;
  344. for ( i = 0; i < numPoints; i++ ) {
  345. const idVec3 &p = points[i];
  346. pCull = 0;
  347. if ( p.x < dNear ) {
  348. pCull = 1;
  349. }
  350. else if ( p.x > dFar ) {
  351. pCull = 2;
  352. }
  353. if ( idMath::Fabs( p.y ) > p.x * leftScale ) {
  354. pCull |= 4 << FLOATSIGNBITSET( p.y );
  355. }
  356. if ( idMath::Fabs( p.z ) > p.x * upScale ) {
  357. pCull |= 16 << FLOATSIGNBITSET( p.z );
  358. }
  359. culled &= pCull;
  360. pointCull[i] = pCull;
  361. }
  362. return ( culled != 0 );
  363. }
  364. /*
  365. ============
  366. idFrustum::CullWinding
  367. ============
  368. */
  369. bool idFrustum::CullWinding( const idWinding &winding ) const {
  370. int i, *pointCull;
  371. idVec3 *localPoints;
  372. idMat3 transpose;
  373. localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
  374. pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
  375. transpose = axis.Transpose();
  376. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  377. localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
  378. }
  379. return CullLocalWinding( localPoints, winding.GetNumPoints(), pointCull );
  380. }
  381. /*
  382. ============
  383. idFrustum::BoundsCullLocalFrustum
  384. Tests if any of the bounding box planes can be used as a separating plane.
  385. ============
  386. */
  387. bool idFrustum::BoundsCullLocalFrustum( const idBounds &bounds, const idFrustum &localFrustum, const idVec3 indexPoints[8], const idVec3 cornerVecs[4] ) const {
  388. int index;
  389. float dx, dy, dz;
  390. dy = -localFrustum.axis[1].x;
  391. dz = -localFrustum.axis[2].x;
  392. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  393. dx = -cornerVecs[index].x;
  394. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  395. if ( indexPoints[index].x < bounds[0].x ) {
  396. return true;
  397. }
  398. dy = localFrustum.axis[1].x;
  399. dz = localFrustum.axis[2].x;
  400. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  401. dx = cornerVecs[index].x;
  402. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  403. if ( indexPoints[index].x > bounds[1].x ) {
  404. return true;
  405. }
  406. dy = -localFrustum.axis[1].y;
  407. dz = -localFrustum.axis[2].y;
  408. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  409. dx = -cornerVecs[index].y;
  410. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  411. if ( indexPoints[index].y < bounds[0].y ) {
  412. return true;
  413. }
  414. dy = localFrustum.axis[1].y;
  415. dz = localFrustum.axis[2].y;
  416. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  417. dx = cornerVecs[index].y;
  418. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  419. if ( indexPoints[index].y > bounds[1].y ) {
  420. return true;
  421. }
  422. dy = -localFrustum.axis[1].z;
  423. dz = -localFrustum.axis[2].z;
  424. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  425. dx = -cornerVecs[index].z;
  426. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  427. if ( indexPoints[index].z < bounds[0].z ) {
  428. return true;
  429. }
  430. dy = localFrustum.axis[1].z;
  431. dz = localFrustum.axis[2].z;
  432. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  433. dx = cornerVecs[index].z;
  434. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  435. if ( indexPoints[index].z > bounds[1].z ) {
  436. return true;
  437. }
  438. return false;
  439. }
  440. /*
  441. ============
  442. idFrustum::LocalLineIntersection
  443. 7 divs
  444. 30 muls
  445. ============
  446. */
  447. bool idFrustum::LocalLineIntersection( const idVec3 &start, const idVec3 &end ) const {
  448. idVec3 dir;
  449. float d1, d2, fstart, fend, lstart, lend, f, x;
  450. float leftScale, upScale;
  451. int startInside = 1;
  452. leftScale = dLeft * invFar;
  453. upScale = dUp * invFar;
  454. dir = end - start;
  455. // test near plane
  456. if ( dNear > 0.0f ) {
  457. d1 = dNear - start.x;
  458. startInside &= FLOATSIGNBITSET( d1 );
  459. if ( FLOATNOTZERO( d1 ) ) {
  460. d2 = dNear - end.x;
  461. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  462. f = d1 / ( d1 - d2 );
  463. if ( idMath::Fabs( start.y + f * dir.y ) <= dNear * leftScale ) {
  464. if ( idMath::Fabs( start.z + f * dir.z ) <= dNear * upScale ) {
  465. return true;
  466. }
  467. }
  468. }
  469. }
  470. }
  471. // test far plane
  472. d1 = start.x - dFar;
  473. startInside &= FLOATSIGNBITSET( d1 );
  474. if ( FLOATNOTZERO( d1 ) ) {
  475. d2 = end.x - dFar;
  476. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  477. f = d1 / ( d1 - d2 );
  478. if ( idMath::Fabs( start.y + f * dir.y ) <= dFar * leftScale ) {
  479. if ( idMath::Fabs( start.z + f * dir.z ) <= dFar * upScale ) {
  480. return true;
  481. }
  482. }
  483. }
  484. }
  485. fstart = dFar * start.y;
  486. fend = dFar * end.y;
  487. lstart = dLeft * start.x;
  488. lend = dLeft * end.x;
  489. // test left plane
  490. d1 = fstart - lstart;
  491. startInside &= FLOATSIGNBITSET( d1 );
  492. if ( FLOATNOTZERO( d1 ) ) {
  493. d2 = fend - lend;
  494. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  495. f = d1 / ( d1 - d2 );
  496. x = start.x + f * dir.x;
  497. if ( x >= dNear && x <= dFar ) {
  498. if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
  499. return true;
  500. }
  501. }
  502. }
  503. }
  504. // test right plane
  505. d1 = -fstart - lstart;
  506. startInside &= FLOATSIGNBITSET( d1 );
  507. if ( FLOATNOTZERO( d1 ) ) {
  508. d2 = -fend - lend;
  509. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  510. f = d1 / ( d1 - d2 );
  511. x = start.x + f * dir.x;
  512. if ( x >= dNear && x <= dFar ) {
  513. if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
  514. return true;
  515. }
  516. }
  517. }
  518. }
  519. fstart = dFar * start.z;
  520. fend = dFar * end.z;
  521. lstart = dUp * start.x;
  522. lend = dUp * end.x;
  523. // test up plane
  524. d1 = fstart - lstart;
  525. startInside &= FLOATSIGNBITSET( d1 );
  526. if ( FLOATNOTZERO( d1 ) ) {
  527. d2 = fend - lend;
  528. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  529. f = d1 / ( d1 - d2 );
  530. x = start.x + f * dir.x;
  531. if ( x >= dNear && x <= dFar ) {
  532. if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
  533. return true;
  534. }
  535. }
  536. }
  537. }
  538. // test down plane
  539. d1 = -fstart - lstart;
  540. startInside &= FLOATSIGNBITSET( d1 );
  541. if ( FLOATNOTZERO( d1 ) ) {
  542. d2 = -fend - lend;
  543. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  544. f = d1 / ( d1 - d2 );
  545. x = start.x + f * dir.x;
  546. if ( x >= dNear && x <= dFar ) {
  547. if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
  548. return true;
  549. }
  550. }
  551. }
  552. }
  553. return ( startInside != 0 );
  554. }
  555. /*
  556. ============
  557. idFrustum::LocalRayIntersection
  558. Returns true if the ray starts inside the frustum.
  559. If there was an intersection scale1 <= scale2
  560. ============
  561. */
  562. bool idFrustum::LocalRayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
  563. idVec3 end;
  564. float d1, d2, fstart, fend, lstart, lend, f, x;
  565. float leftScale, upScale;
  566. int startInside = 1;
  567. leftScale = dLeft * invFar;
  568. upScale = dUp * invFar;
  569. end = start + dir;
  570. scale1 = idMath::INFINITY;
  571. scale2 = -idMath::INFINITY;
  572. // test near plane
  573. if ( dNear > 0.0f ) {
  574. d1 = dNear - start.x;
  575. startInside &= FLOATSIGNBITSET( d1 );
  576. d2 = dNear - end.x;
  577. if ( d1 != d2 ) {
  578. f = d1 / ( d1 - d2 );
  579. if ( idMath::Fabs( start.y + f * dir.y ) <= dNear * leftScale ) {
  580. if ( idMath::Fabs( start.z + f * dir.z ) <= dNear * upScale ) {
  581. if ( f < scale1 ) scale1 = f;
  582. if ( f > scale2 ) scale2 = f;
  583. }
  584. }
  585. }
  586. }
  587. // test far plane
  588. d1 = start.x - dFar;
  589. startInside &= FLOATSIGNBITSET( d1 );
  590. d2 = end.x - dFar;
  591. if ( d1 != d2 ) {
  592. f = d1 / ( d1 - d2 );
  593. if ( idMath::Fabs( start.y + f * dir.y ) <= dFar * leftScale ) {
  594. if ( idMath::Fabs( start.z + f * dir.z ) <= dFar * upScale ) {
  595. if ( f < scale1 ) scale1 = f;
  596. if ( f > scale2 ) scale2 = f;
  597. }
  598. }
  599. }
  600. fstart = dFar * start.y;
  601. fend = dFar * end.y;
  602. lstart = dLeft * start.x;
  603. lend = dLeft * end.x;
  604. // test left plane
  605. d1 = fstart - lstart;
  606. startInside &= FLOATSIGNBITSET( d1 );
  607. d2 = fend - lend;
  608. if ( d1 != d2 ) {
  609. f = d1 / ( d1 - d2 );
  610. x = start.x + f * dir.x;
  611. if ( x >= dNear && x <= dFar ) {
  612. if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
  613. if ( f < scale1 ) scale1 = f;
  614. if ( f > scale2 ) scale2 = f;
  615. }
  616. }
  617. }
  618. // test right plane
  619. d1 = -fstart - lstart;
  620. startInside &= FLOATSIGNBITSET( d1 );
  621. d2 = -fend - lend;
  622. if ( d1 != d2 ) {
  623. f = d1 / ( d1 - d2 );
  624. x = start.x + f * dir.x;
  625. if ( x >= dNear && x <= dFar ) {
  626. if ( idMath::Fabs( start.z + f * dir.z ) <= x * upScale ) {
  627. if ( f < scale1 ) scale1 = f;
  628. if ( f > scale2 ) scale2 = f;
  629. }
  630. }
  631. }
  632. fstart = dFar * start.z;
  633. fend = dFar * end.z;
  634. lstart = dUp * start.x;
  635. lend = dUp * end.x;
  636. // test up plane
  637. d1 = fstart - lstart;
  638. startInside &= FLOATSIGNBITSET( d1 );
  639. d2 = fend - lend;
  640. if ( d1 != d2 ) {
  641. f = d1 / ( d1 - d2 );
  642. x = start.x + f * dir.x;
  643. if ( x >= dNear && x <= dFar ) {
  644. if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
  645. if ( f < scale1 ) scale1 = f;
  646. if ( f > scale2 ) scale2 = f;
  647. }
  648. }
  649. }
  650. // test down plane
  651. d1 = -fstart - lstart;
  652. startInside &= FLOATSIGNBITSET( d1 );
  653. d2 = -fend - lend;
  654. if ( d1 != d2 ) {
  655. f = d1 / ( d1 - d2 );
  656. x = start.x + f * dir.x;
  657. if ( x >= dNear && x <= dFar ) {
  658. if ( idMath::Fabs( start.y + f * dir.y ) <= x * leftScale ) {
  659. if ( f < scale1 ) scale1 = f;
  660. if ( f > scale2 ) scale2 = f;
  661. }
  662. }
  663. }
  664. return ( startInside != 0 );
  665. }
  666. /*
  667. ============
  668. idFrustum::ContainsPoint
  669. ============
  670. */
  671. bool idFrustum::ContainsPoint( const idVec3 &point ) const {
  672. return !CullPoint( point );
  673. }
  674. /*
  675. ============
  676. idFrustum::LocalFrustumIntersectsFrustum
  677. ============
  678. */
  679. bool idFrustum::LocalFrustumIntersectsFrustum( const idVec3 points[8], const bool testFirstSide ) const {
  680. int i;
  681. // test if any edges of the other frustum intersect this frustum
  682. for ( i = 0; i < 4; i++ ) {
  683. if ( LocalLineIntersection( points[i], points[4+i] ) ) {
  684. return true;
  685. }
  686. }
  687. if ( testFirstSide ) {
  688. for ( i = 0; i < 4; i++ ) {
  689. if ( LocalLineIntersection( points[i], points[(i+1)&3] ) ) {
  690. return true;
  691. }
  692. }
  693. }
  694. for ( i = 0; i < 4; i++ ) {
  695. if ( LocalLineIntersection( points[4+i], points[4+((i+1)&3)] ) ) {
  696. return true;
  697. }
  698. }
  699. return false;
  700. }
  701. /*
  702. ============
  703. idFrustum::LocalFrustumIntersectsBounds
  704. ============
  705. */
  706. bool idFrustum::LocalFrustumIntersectsBounds( const idVec3 points[8], const idBounds &bounds ) const {
  707. int i;
  708. // test if any edges of the other frustum intersect this frustum
  709. for ( i = 0; i < 4; i++ ) {
  710. if ( bounds.LineIntersection( points[i], points[4+i] ) ) {
  711. return true;
  712. }
  713. }
  714. if ( dNear > 0.0f ) {
  715. for ( i = 0; i < 4; i++ ) {
  716. if ( bounds.LineIntersection( points[i], points[(i+1)&3] ) ) {
  717. return true;
  718. }
  719. }
  720. }
  721. for ( i = 0; i < 4; i++ ) {
  722. if ( bounds.LineIntersection( points[4+i], points[4+((i+1)&3)] ) ) {
  723. return true;
  724. }
  725. }
  726. return false;
  727. }
  728. /*
  729. ============
  730. idFrustum::IntersectsBounds
  731. ============
  732. */
  733. bool idFrustum::IntersectsBounds( const idBounds &bounds ) const {
  734. idVec3 localOrigin, center, extents;
  735. idMat3 localAxis;
  736. center = ( bounds[0] + bounds[1] ) * 0.5f;
  737. extents = bounds[1] - center;
  738. localOrigin = ( center - origin ) * axis.Transpose();
  739. localAxis = axis.Transpose();
  740. if ( CullLocalBox( localOrigin, extents, localAxis ) ) {
  741. return false;
  742. }
  743. idVec3 indexPoints[8], cornerVecs[4];
  744. ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  745. if ( BoundsCullLocalFrustum( bounds, *this, indexPoints, cornerVecs ) ) {
  746. return false;
  747. }
  748. idSwap( indexPoints[2], indexPoints[3] );
  749. idSwap( indexPoints[6], indexPoints[7] );
  750. if ( LocalFrustumIntersectsBounds( indexPoints, bounds ) ) {
  751. return true;
  752. }
  753. BoxToPoints( localOrigin, extents, localAxis, indexPoints );
  754. if ( LocalFrustumIntersectsFrustum( indexPoints, true ) ) {
  755. return true;
  756. }
  757. return false;
  758. }
  759. /*
  760. ============
  761. idFrustum::IntersectsBox
  762. ============
  763. */
  764. bool idFrustum::IntersectsBox( const idBox &box ) const {
  765. idVec3 localOrigin;
  766. idMat3 localAxis;
  767. localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
  768. localAxis = box.GetAxis() * axis.Transpose();
  769. if ( CullLocalBox( localOrigin, box.GetExtents(), localAxis ) ) {
  770. return false;
  771. }
  772. idVec3 indexPoints[8], cornerVecs[4];
  773. idFrustum localFrustum;
  774. localFrustum = *this;
  775. localFrustum.origin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
  776. localFrustum.axis = axis * box.GetAxis().Transpose();
  777. localFrustum.ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  778. if ( BoundsCullLocalFrustum( idBounds( -box.GetExtents(), box.GetExtents() ), localFrustum, indexPoints, cornerVecs ) ) {
  779. return false;
  780. }
  781. idSwap( indexPoints[2], indexPoints[3] );
  782. idSwap( indexPoints[6], indexPoints[7] );
  783. if ( LocalFrustumIntersectsBounds( indexPoints, idBounds( -box.GetExtents(), box.GetExtents() ) ) ) {
  784. return true;
  785. }
  786. BoxToPoints( localOrigin, box.GetExtents(), localAxis, indexPoints );
  787. if ( LocalFrustumIntersectsFrustum( indexPoints, true ) ) {
  788. return true;
  789. }
  790. return false;
  791. }
  792. /*
  793. ============
  794. idFrustum::IntersectsSphere
  795. FIXME: test this
  796. ============
  797. */
  798. #define VORONOI_INDEX( x, y, z ) ( x + y * 3 + z * 9 )
  799. bool idFrustum::IntersectsSphere( const idSphere &sphere ) const {
  800. int index, x, y, z;
  801. float scale, r, d;
  802. idVec3 p, dir, points[8];
  803. if ( CullSphere( sphere ) ) {
  804. return false;
  805. }
  806. x = y = z = 0;
  807. dir.Zero();
  808. p = ( sphere.GetOrigin() - origin ) * axis.Transpose();
  809. if ( p.x <= dNear ) {
  810. scale = dNear * invFar;
  811. dir.y = idMath::Fabs( p.y ) - dLeft * scale;
  812. dir.z = idMath::Fabs( p.z ) - dUp * scale;
  813. }
  814. else if ( p.x >= dFar ) {
  815. dir.y = idMath::Fabs( p.y ) - dLeft;
  816. dir.z = idMath::Fabs( p.z ) - dUp;
  817. }
  818. else {
  819. scale = p.x * invFar;
  820. dir.y = idMath::Fabs( p.y ) - dLeft * scale;
  821. dir.z = idMath::Fabs( p.z ) - dUp * scale;
  822. }
  823. if ( dir.y > 0.0f ) {
  824. y = ( 1 + FLOATSIGNBITNOTSET( p.y ) );
  825. }
  826. if ( dir.z > 0.0f ) {
  827. z = ( 1 + FLOATSIGNBITNOTSET( p.z ) );
  828. }
  829. if ( p.x < dNear ) {
  830. scale = dLeft * dNear * invFar;
  831. if ( p.x < dNear + ( scale - p.y ) * scale * invFar ) {
  832. scale = dUp * dNear * invFar;
  833. if ( p.x < dNear + ( scale - p.z ) * scale * invFar ) {
  834. x = 1;
  835. }
  836. }
  837. }
  838. else {
  839. if ( p.x > dFar ) {
  840. x = 2;
  841. }
  842. else if ( p.x > dFar + ( dLeft - p.y ) * dLeft * invFar ) {
  843. x = 2;
  844. }
  845. else if ( p.x > dFar + ( dUp - p.z ) * dUp * invFar ) {
  846. x = 2;
  847. }
  848. }
  849. r = sphere.GetRadius();
  850. index = VORONOI_INDEX( x, y, z );
  851. switch( index ) {
  852. case VORONOI_INDEX( 0, 0, 0 ): return true;
  853. case VORONOI_INDEX( 1, 0, 0 ): return ( dNear - p.x < r );
  854. case VORONOI_INDEX( 2, 0, 0 ): return ( p.x - dFar < r );
  855. case VORONOI_INDEX( 0, 1, 0 ): d = dFar * p.y - dLeft * p.x; return ( d * d < r * r * ( dFar * dFar + dLeft * dLeft ) );
  856. case VORONOI_INDEX( 0, 2, 0 ): d = -dFar * p.z - dLeft * p.x; return ( d * d < r * r * ( dFar * dFar + dLeft * dLeft ) );
  857. case VORONOI_INDEX( 0, 0, 1 ): d = dFar * p.z - dUp * p.x; return ( d * d < r * r * ( dFar * dFar + dUp * dUp ) );
  858. case VORONOI_INDEX( 0, 0, 2 ): d = -dFar * p.z - dUp * p.x; return ( d * d < r * r * ( dFar * dFar + dUp * dUp ) );
  859. default: {
  860. ToIndexPoints( points );
  861. switch( index ) {
  862. case VORONOI_INDEX( 1, 1, 1 ): return sphere.ContainsPoint( points[0] );
  863. case VORONOI_INDEX( 2, 1, 1 ): return sphere.ContainsPoint( points[4] );
  864. case VORONOI_INDEX( 1, 2, 1 ): return sphere.ContainsPoint( points[1] );
  865. case VORONOI_INDEX( 2, 2, 1 ): return sphere.ContainsPoint( points[5] );
  866. case VORONOI_INDEX( 1, 1, 2 ): return sphere.ContainsPoint( points[2] );
  867. case VORONOI_INDEX( 2, 1, 2 ): return sphere.ContainsPoint( points[6] );
  868. case VORONOI_INDEX( 1, 2, 2 ): return sphere.ContainsPoint( points[3] );
  869. case VORONOI_INDEX( 2, 2, 2 ): return sphere.ContainsPoint( points[7] );
  870. case VORONOI_INDEX( 1, 1, 0 ): return sphere.LineIntersection( points[0], points[2] );
  871. case VORONOI_INDEX( 2, 1, 0 ): return sphere.LineIntersection( points[4], points[6] );
  872. case VORONOI_INDEX( 1, 2, 0 ): return sphere.LineIntersection( points[1], points[3] );
  873. case VORONOI_INDEX( 2, 2, 0 ): return sphere.LineIntersection( points[5], points[7] );
  874. case VORONOI_INDEX( 1, 0, 1 ): return sphere.LineIntersection( points[0], points[1] );
  875. case VORONOI_INDEX( 2, 0, 1 ): return sphere.LineIntersection( points[4], points[5] );
  876. case VORONOI_INDEX( 0, 1, 1 ): return sphere.LineIntersection( points[0], points[4] );
  877. case VORONOI_INDEX( 0, 2, 1 ): return sphere.LineIntersection( points[1], points[5] );
  878. case VORONOI_INDEX( 1, 0, 2 ): return sphere.LineIntersection( points[2], points[3] );
  879. case VORONOI_INDEX( 2, 0, 2 ): return sphere.LineIntersection( points[6], points[7] );
  880. case VORONOI_INDEX( 0, 1, 2 ): return sphere.LineIntersection( points[2], points[6] );
  881. case VORONOI_INDEX( 0, 2, 2 ): return sphere.LineIntersection( points[3], points[7] );
  882. }
  883. break;
  884. }
  885. }
  886. return false;
  887. }
  888. /*
  889. ============
  890. idFrustum::IntersectsFrustum
  891. ============
  892. */
  893. bool idFrustum::IntersectsFrustum( const idFrustum &frustum ) const {
  894. idVec3 indexPoints2[8], cornerVecs2[4];
  895. idFrustum localFrustum2;
  896. localFrustum2 = frustum;
  897. localFrustum2.origin = ( frustum.origin - origin ) * axis.Transpose();
  898. localFrustum2.axis = frustum.axis * axis.Transpose();
  899. localFrustum2.ToIndexPointsAndCornerVecs( indexPoints2, cornerVecs2 );
  900. if ( CullLocalFrustum( localFrustum2, indexPoints2, cornerVecs2 ) ) {
  901. return false;
  902. }
  903. idVec3 indexPoints1[8], cornerVecs1[4];
  904. idFrustum localFrustum1;
  905. localFrustum1 = *this;
  906. localFrustum1.origin = ( origin - frustum.origin ) * frustum.axis.Transpose();
  907. localFrustum1.axis = axis * frustum.axis.Transpose();
  908. localFrustum1.ToIndexPointsAndCornerVecs( indexPoints1, cornerVecs1 );
  909. if ( frustum.CullLocalFrustum( localFrustum1, indexPoints1, cornerVecs1 ) ) {
  910. return false;
  911. }
  912. idSwap( indexPoints2[2], indexPoints2[3] );
  913. idSwap( indexPoints2[6], indexPoints2[7] );
  914. if ( LocalFrustumIntersectsFrustum( indexPoints2, ( localFrustum2.dNear > 0.0f ) ) ) {
  915. return true;
  916. }
  917. idSwap( indexPoints1[2], indexPoints1[3] );
  918. idSwap( indexPoints1[6], indexPoints1[7] );
  919. if ( frustum.LocalFrustumIntersectsFrustum( indexPoints1, ( localFrustum1.dNear > 0.0f ) ) ) {
  920. return true;
  921. }
  922. return false;
  923. }
  924. /*
  925. ============
  926. idFrustum::IntersectsWinding
  927. ============
  928. */
  929. bool idFrustum::IntersectsWinding( const idWinding &winding ) const {
  930. int i, j, *pointCull;
  931. float min, max;
  932. idVec3 *localPoints, indexPoints[8], cornerVecs[4];
  933. idMat3 transpose;
  934. idPlane plane;
  935. localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
  936. pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
  937. transpose = axis.Transpose();
  938. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  939. localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
  940. }
  941. // if the winding is culled
  942. if ( CullLocalWinding( localPoints, winding.GetNumPoints(), pointCull ) ) {
  943. return false;
  944. }
  945. winding.GetPlane( plane );
  946. ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  947. AxisProjection( indexPoints, cornerVecs, plane.Normal(), min, max );
  948. // if the frustum does not cross the winding plane
  949. if ( min + plane[3] > 0.0f || max + plane[3] < 0.0f ) {
  950. return false;
  951. }
  952. // test if any of the winding edges goes through the frustum
  953. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  954. j = (i+1)%winding.GetNumPoints();
  955. if ( !( pointCull[i] & pointCull[j] ) ) {
  956. if ( LocalLineIntersection( localPoints[i], localPoints[j] ) ) {
  957. return true;
  958. }
  959. }
  960. }
  961. idSwap( indexPoints[2], indexPoints[3] );
  962. idSwap( indexPoints[6], indexPoints[7] );
  963. // test if any edges of the frustum intersect the winding
  964. for ( i = 0; i < 4; i++ ) {
  965. if ( winding.LineIntersection( plane, indexPoints[i], indexPoints[4+i] ) ) {
  966. return true;
  967. }
  968. }
  969. if ( dNear > 0.0f ) {
  970. for ( i = 0; i < 4; i++ ) {
  971. if ( winding.LineIntersection( plane, indexPoints[i], indexPoints[(i+1)&3] ) ) {
  972. return true;
  973. }
  974. }
  975. }
  976. for ( i = 0; i < 4; i++ ) {
  977. if ( winding.LineIntersection( plane, indexPoints[4+i], indexPoints[4+((i+1)&3)] ) ) {
  978. return true;
  979. }
  980. }
  981. return false;
  982. }
  983. /*
  984. ============
  985. idFrustum::LineIntersection
  986. Returns true if the line intersects the box between the start and end point.
  987. ============
  988. */
  989. bool idFrustum::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
  990. return LocalLineIntersection( ( start - origin ) * axis.Transpose(), ( end - origin ) * axis.Transpose() );
  991. }
  992. /*
  993. ============
  994. idFrustum::RayIntersection
  995. Returns true if the ray intersects the bounds.
  996. The ray can intersect the bounds in both directions from the start point.
  997. If start is inside the frustum then scale1 < 0 and scale2 > 0.
  998. ============
  999. */
  1000. bool idFrustum::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
  1001. if ( LocalRayIntersection( ( start - origin ) * axis.Transpose(), dir * axis.Transpose(), scale1, scale2 ) ) {
  1002. return true;
  1003. }
  1004. if ( scale1 <= scale2 ) {
  1005. return true;
  1006. }
  1007. return false;
  1008. }
  1009. /*
  1010. ============
  1011. idFrustum::FromProjection
  1012. Creates a frustum which contains the projection of the bounds.
  1013. ============
  1014. */
  1015. bool idFrustum::FromProjection( const idBounds &bounds, const idVec3 &projectionOrigin, const float dFar ) {
  1016. return FromProjection( idBox( bounds, vec3_origin, mat3_identity ), projectionOrigin, dFar );
  1017. }
  1018. /*
  1019. ============
  1020. idFrustum::FromProjection
  1021. Creates a frustum which contains the projection of the box.
  1022. ============
  1023. */
  1024. bool idFrustum::FromProjection( const idBox &box, const idVec3 &projectionOrigin, const float dFar ) {
  1025. int i, bestAxis;
  1026. float value, bestValue;
  1027. idVec3 dir;
  1028. assert( dFar > 0.0f );
  1029. this->dNear = this->dFar = this->invFar = 0.0f;
  1030. dir = box.GetCenter() - projectionOrigin;
  1031. if ( dir.Normalize() == 0.0f ) {
  1032. return false;
  1033. }
  1034. bestAxis = 0;
  1035. bestValue = idMath::Fabs( box.GetAxis()[0] * dir );
  1036. for ( i = 1; i < 3; i++ ) {
  1037. value = idMath::Fabs( box.GetAxis()[i] * dir );
  1038. if ( value * box.GetExtents()[bestAxis] * box.GetExtents()[bestAxis] < bestValue * box.GetExtents()[i] * box.GetExtents()[i] ) {
  1039. bestValue = value;
  1040. bestAxis = i;
  1041. }
  1042. }
  1043. #if 1
  1044. int j, minX, minY, maxY, minZ, maxZ;
  1045. idVec3 points[8];
  1046. minX = minY = maxY = minZ = maxZ = 0;
  1047. for ( j = 0; j < 2; j++ ) {
  1048. axis[0] = dir;
  1049. axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
  1050. axis[1].Normalize();
  1051. axis[2].Cross( axis[0], axis[1] );
  1052. BoxToPoints( ( box.GetCenter() - projectionOrigin ) * axis.Transpose(), box.GetExtents(), box.GetAxis() * axis.Transpose(), points );
  1053. if ( points[0].x <= 1.0f ) {
  1054. return false;
  1055. }
  1056. minX = minY = maxY = minZ = maxZ = 0;
  1057. for ( i = 1; i < 8; i++ ) {
  1058. if ( points[i].x <= 1.0f ) {
  1059. return false;
  1060. }
  1061. if ( points[i].x < points[minX].x ) {
  1062. minX = i;
  1063. }
  1064. if ( points[minY].x * points[i].y < points[i].x * points[minY].y ) {
  1065. minY = i;
  1066. } else if ( points[maxY].x * points[i].y > points[i].x * points[maxY].y ) {
  1067. maxY = i;
  1068. }
  1069. if ( points[minZ].x * points[i].z < points[i].x * points[minZ].z ) {
  1070. minZ = i;
  1071. } else if ( points[maxZ].x * points[i].z > points[i].x * points[maxZ].z ) {
  1072. maxZ = i;
  1073. }
  1074. }
  1075. if ( j == 0 ) {
  1076. dir += idMath::Tan16( 0.5f * ( idMath::ATan16( points[minY].y, points[minY].x ) + idMath::ATan16( points[maxY].y, points[maxY].x ) ) ) * axis[1];
  1077. dir += idMath::Tan16( 0.5f * ( idMath::ATan16( points[minZ].z, points[minZ].x ) + idMath::ATan16( points[maxZ].z, points[maxZ].x ) ) ) * axis[2];
  1078. dir.Normalize();
  1079. }
  1080. }
  1081. this->origin = projectionOrigin;
  1082. this->dNear = points[minX].x;
  1083. this->dFar = dFar;
  1084. this->dLeft = Max( idMath::Fabs( points[minY].y / points[minY].x ), idMath::Fabs( points[maxY].y / points[maxY].x ) ) * dFar;
  1085. this->dUp = Max( idMath::Fabs( points[minZ].z / points[minZ].x ), idMath::Fabs( points[maxZ].z / points[maxZ].x ) ) * dFar;
  1086. this->invFar = 1.0f / dFar;
  1087. #elif 1
  1088. int j;
  1089. float f, x;
  1090. idBounds b;
  1091. idVec3 points[8];
  1092. for ( j = 0; j < 2; j++ ) {
  1093. axis[0] = dir;
  1094. axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
  1095. axis[1].Normalize();
  1096. axis[2].Cross( axis[0], axis[1] );
  1097. BoxToPoints( ( box.GetCenter() - projectionOrigin ) * axis.Transpose(), box.GetExtents(), box.GetAxis() * axis.Transpose(), points );
  1098. b.Clear();
  1099. for ( i = 0; i < 8; i++ ) {
  1100. x = points[i].x;
  1101. if ( x <= 1.0f ) {
  1102. return false;
  1103. }
  1104. f = 1.0f / x;
  1105. points[i].y *= f;
  1106. points[i].z *= f;
  1107. b.AddPoint( points[i] );
  1108. }
  1109. if ( j == 0 ) {
  1110. dir += idMath::Tan16( 0.5f * ( idMath::ATan16( b[1][1] ) + idMath::ATan16( b[0][1] ) ) ) * axis[1];
  1111. dir += idMath::Tan16( 0.5f * ( idMath::ATan16( b[1][2] ) + idMath::ATan16( b[0][2] ) ) ) * axis[2];
  1112. dir.Normalize();
  1113. }
  1114. }
  1115. this->origin = projectionOrigin;
  1116. this->dNear = b[0][0];
  1117. this->dFar = dFar;
  1118. this->dLeft = Max( idMath::Fabs( b[0][1] ), idMath::Fabs( b[1][1] ) ) * dFar;
  1119. this->dUp = Max( idMath::Fabs( b[0][2] ), idMath::Fabs( b[1][2] ) ) * dFar;
  1120. this->invFar = 1.0f / dFar;
  1121. #else
  1122. float dist;
  1123. idVec3 org;
  1124. axis[0] = dir;
  1125. axis[1] = box.GetAxis()[bestAxis] - ( box.GetAxis()[bestAxis] * axis[0] ) * axis[0];
  1126. axis[1].Normalize();
  1127. axis[2].Cross( axis[0], axis[1] );
  1128. for ( i = 0; i < 3; i++ ) {
  1129. dist[i] = idMath::Fabs( box.GetExtents()[0] * ( axis[i] * box.GetAxis()[0] ) ) +
  1130. idMath::Fabs( box.GetExtents()[1] * ( axis[i] * box.GetAxis()[1] ) ) +
  1131. idMath::Fabs( box.GetExtents()[2] * ( axis[i] * box.GetAxis()[2] ) );
  1132. }
  1133. dist[0] = axis[0] * ( box.GetCenter() - projectionOrigin ) - dist[0];
  1134. if ( dist[0] <= 1.0f ) {
  1135. return false;
  1136. }
  1137. float invDist = 1.0f / dist[0];
  1138. this->origin = projectionOrigin;
  1139. this->dNear = dist[0];
  1140. this->dFar = dFar;
  1141. this->dLeft = dist[1] * invDist * dFar;
  1142. this->dUp = dist[2] * invDist * dFar;
  1143. this->invFar = 1.0f / dFar;
  1144. #endif
  1145. return true;
  1146. }
  1147. /*
  1148. ============
  1149. idFrustum::FromProjection
  1150. Creates a frustum which contains the projection of the sphere.
  1151. ============
  1152. */
  1153. bool idFrustum::FromProjection( const idSphere &sphere, const idVec3 &projectionOrigin, const float dFar ) {
  1154. idVec3 dir;
  1155. float d, r, s, x, y;
  1156. assert( dFar > 0.0f );
  1157. dir = sphere.GetOrigin() - projectionOrigin;
  1158. d = dir.Normalize();
  1159. r = sphere.GetRadius();
  1160. if ( d <= r + 1.0f ) {
  1161. this->dNear = this->dFar = this->invFar = 0.0f;
  1162. return false;
  1163. }
  1164. origin = projectionOrigin;
  1165. axis = dir.ToMat3();
  1166. s = idMath::Sqrt( d * d - r * r );
  1167. x = r / d * s;
  1168. y = idMath::Sqrt( s * s - x * x );
  1169. this->dNear = d - r;
  1170. this->dFar = dFar;
  1171. this->dLeft = x / y * dFar;
  1172. this->dUp = dLeft;
  1173. this->invFar = 1.0f / dFar;
  1174. return true;
  1175. }
  1176. /*
  1177. ============
  1178. idFrustum::ConstrainToBounds
  1179. Returns false if no part of the bounds extends beyond the near plane.
  1180. ============
  1181. */
  1182. bool idFrustum::ConstrainToBounds( const idBounds &bounds ) {
  1183. float min, max, newdFar;
  1184. bounds.AxisProjection( axis[0], min, max );
  1185. newdFar = max - axis[0] * origin;
  1186. if ( newdFar <= dNear ) {
  1187. MoveFarDistance( dNear + 1.0f );
  1188. return false;
  1189. }
  1190. MoveFarDistance( newdFar );
  1191. return true;
  1192. }
  1193. /*
  1194. ============
  1195. idFrustum::ConstrainToBox
  1196. Returns false if no part of the box extends beyond the near plane.
  1197. ============
  1198. */
  1199. bool idFrustum::ConstrainToBox( const idBox &box ) {
  1200. float min, max, newdFar;
  1201. box.AxisProjection( axis[0], min, max );
  1202. newdFar = max - axis[0] * origin;
  1203. if ( newdFar <= dNear ) {
  1204. MoveFarDistance( dNear + 1.0f );
  1205. return false;
  1206. }
  1207. MoveFarDistance( newdFar );
  1208. return true;
  1209. }
  1210. /*
  1211. ============
  1212. idFrustum::ConstrainToSphere
  1213. Returns false if no part of the sphere extends beyond the near plane.
  1214. ============
  1215. */
  1216. bool idFrustum::ConstrainToSphere( const idSphere &sphere ) {
  1217. float min, max, newdFar;
  1218. sphere.AxisProjection( axis[0], min, max );
  1219. newdFar = max - axis[0] * origin;
  1220. if ( newdFar <= dNear ) {
  1221. MoveFarDistance( dNear + 1.0f );
  1222. return false;
  1223. }
  1224. MoveFarDistance( newdFar );
  1225. return true;
  1226. }
  1227. /*
  1228. ============
  1229. idFrustum::ConstrainToFrustum
  1230. Returns false if no part of the frustum extends beyond the near plane.
  1231. ============
  1232. */
  1233. bool idFrustum::ConstrainToFrustum( const idFrustum &frustum ) {
  1234. float min, max, newdFar;
  1235. frustum.AxisProjection( axis[0], min, max );
  1236. newdFar = max - axis[0] * origin;
  1237. if ( newdFar <= dNear ) {
  1238. MoveFarDistance( dNear + 1.0f );
  1239. return false;
  1240. }
  1241. MoveFarDistance( newdFar );
  1242. return true;
  1243. }
  1244. /*
  1245. ============
  1246. idFrustum::ToPlanes
  1247. planes point outwards
  1248. ============
  1249. */
  1250. void idFrustum::ToPlanes( idPlane planes[6] ) const {
  1251. int i;
  1252. idVec3 scaled[2];
  1253. idVec3 points[4];
  1254. planes[0].Normal() = -axis[0];
  1255. planes[0].SetDist( -dNear );
  1256. planes[1].Normal() = axis[0];
  1257. planes[1].SetDist( dFar );
  1258. scaled[0] = axis[1] * dLeft;
  1259. scaled[1] = axis[2] * dUp;
  1260. points[0] = scaled[0] + scaled[1];
  1261. points[1] = -scaled[0] + scaled[1];
  1262. points[2] = -scaled[0] - scaled[1];
  1263. points[3] = scaled[0] - scaled[1];
  1264. for ( i = 0; i < 4; i++ ) {
  1265. planes[i+2].Normal() = points[i].Cross( points[(i+1)&3] - points[i] );
  1266. planes[i+2].Normalize();
  1267. planes[i+2].FitThroughPoint( points[i] );
  1268. }
  1269. }
  1270. /*
  1271. ============
  1272. idFrustum::ToPoints
  1273. ============
  1274. */
  1275. void idFrustum::ToPoints( idVec3 points[8] ) const {
  1276. idMat3 scaled;
  1277. scaled[0] = origin + axis[0] * dNear;
  1278. scaled[1] = axis[1] * ( dLeft * dNear * invFar );
  1279. scaled[2] = axis[2] * ( dUp * dNear * invFar );
  1280. points[0] = scaled[0] + scaled[1];
  1281. points[1] = scaled[0] - scaled[1];
  1282. points[2] = points[1] - scaled[2];
  1283. points[3] = points[0] - scaled[2];
  1284. points[0] += scaled[2];
  1285. points[1] += scaled[2];
  1286. scaled[0] = origin + axis[0] * dFar;
  1287. scaled[1] = axis[1] * dLeft;
  1288. scaled[2] = axis[2] * dUp;
  1289. points[4] = scaled[0] + scaled[1];
  1290. points[5] = scaled[0] - scaled[1];
  1291. points[6] = points[5] - scaled[2];
  1292. points[7] = points[4] - scaled[2];
  1293. points[4] += scaled[2];
  1294. points[5] += scaled[2];
  1295. }
  1296. /*
  1297. ============
  1298. idFrustum::ToClippedPoints
  1299. ============
  1300. */
  1301. void idFrustum::ToClippedPoints( const float fractions[4], idVec3 points[8] ) const {
  1302. idMat3 scaled;
  1303. scaled[0] = origin + axis[0] * dNear;
  1304. scaled[1] = axis[1] * ( dLeft * dNear * invFar );
  1305. scaled[2] = axis[2] * ( dUp * dNear * invFar );
  1306. points[0] = scaled[0] + scaled[1];
  1307. points[1] = scaled[0] - scaled[1];
  1308. points[2] = points[1] - scaled[2];
  1309. points[3] = points[0] - scaled[2];
  1310. points[0] += scaled[2];
  1311. points[1] += scaled[2];
  1312. scaled[0] = axis[0] * dFar;
  1313. scaled[1] = axis[1] * dLeft;
  1314. scaled[2] = axis[2] * dUp;
  1315. points[4] = scaled[0] + scaled[1];
  1316. points[5] = scaled[0] - scaled[1];
  1317. points[6] = points[5] - scaled[2];
  1318. points[7] = points[4] - scaled[2];
  1319. points[4] += scaled[2];
  1320. points[5] += scaled[2];
  1321. points[4] = origin + fractions[0] * points[4];
  1322. points[5] = origin + fractions[1] * points[5];
  1323. points[6] = origin + fractions[2] * points[6];
  1324. points[7] = origin + fractions[3] * points[7];
  1325. }
  1326. /*
  1327. ============
  1328. idFrustum::ToIndexPoints
  1329. ============
  1330. */
  1331. void idFrustum::ToIndexPoints( idVec3 indexPoints[8] ) const {
  1332. idMat3 scaled;
  1333. scaled[0] = origin + axis[0] * dNear;
  1334. scaled[1] = axis[1] * ( dLeft * dNear * invFar );
  1335. scaled[2] = axis[2] * ( dUp * dNear * invFar );
  1336. indexPoints[0] = scaled[0] - scaled[1];
  1337. indexPoints[2] = scaled[0] + scaled[1];
  1338. indexPoints[1] = indexPoints[0] + scaled[2];
  1339. indexPoints[3] = indexPoints[2] + scaled[2];
  1340. indexPoints[0] -= scaled[2];
  1341. indexPoints[2] -= scaled[2];
  1342. scaled[0] = origin + axis[0] * dFar;
  1343. scaled[1] = axis[1] * dLeft;
  1344. scaled[2] = axis[2] * dUp;
  1345. indexPoints[4] = scaled[0] - scaled[1];
  1346. indexPoints[6] = scaled[0] + scaled[1];
  1347. indexPoints[5] = indexPoints[4] + scaled[2];
  1348. indexPoints[7] = indexPoints[6] + scaled[2];
  1349. indexPoints[4] -= scaled[2];
  1350. indexPoints[6] -= scaled[2];
  1351. }
  1352. /*
  1353. ============
  1354. idFrustum::ToIndexPointsAndCornerVecs
  1355. 22 muls
  1356. ============
  1357. */
  1358. void idFrustum::ToIndexPointsAndCornerVecs( idVec3 indexPoints[8], idVec3 cornerVecs[4] ) const {
  1359. idMat3 scaled;
  1360. scaled[0] = origin + axis[0] * dNear;
  1361. scaled[1] = axis[1] * ( dLeft * dNear * invFar );
  1362. scaled[2] = axis[2] * ( dUp * dNear * invFar );
  1363. indexPoints[0] = scaled[0] - scaled[1];
  1364. indexPoints[2] = scaled[0] + scaled[1];
  1365. indexPoints[1] = indexPoints[0] + scaled[2];
  1366. indexPoints[3] = indexPoints[2] + scaled[2];
  1367. indexPoints[0] -= scaled[2];
  1368. indexPoints[2] -= scaled[2];
  1369. scaled[0] = axis[0] * dFar;
  1370. scaled[1] = axis[1] * dLeft;
  1371. scaled[2] = axis[2] * dUp;
  1372. cornerVecs[0] = scaled[0] - scaled[1];
  1373. cornerVecs[2] = scaled[0] + scaled[1];
  1374. cornerVecs[1] = cornerVecs[0] + scaled[2];
  1375. cornerVecs[3] = cornerVecs[2] + scaled[2];
  1376. cornerVecs[0] -= scaled[2];
  1377. cornerVecs[2] -= scaled[2];
  1378. indexPoints[4] = cornerVecs[0] + origin;
  1379. indexPoints[5] = cornerVecs[1] + origin;
  1380. indexPoints[6] = cornerVecs[2] + origin;
  1381. indexPoints[7] = cornerVecs[3] + origin;
  1382. }
  1383. /*
  1384. ============
  1385. idFrustum::AxisProjection
  1386. 18 muls
  1387. ============
  1388. */
  1389. void idFrustum::AxisProjection( const idVec3 indexPoints[8], const idVec3 cornerVecs[4], const idVec3 &dir, float &min, float &max ) const {
  1390. float dx, dy, dz;
  1391. int index;
  1392. dy = dir.x * axis[1].x + dir.y * axis[1].y + dir.z * axis[1].z;
  1393. dz = dir.x * axis[2].x + dir.y * axis[2].y + dir.z * axis[2].z;
  1394. index = ( FLOATSIGNBITSET( dy ) << 1 ) | FLOATSIGNBITSET( dz );
  1395. dx = dir.x * cornerVecs[index].x + dir.y * cornerVecs[index].y + dir.z * cornerVecs[index].z;
  1396. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  1397. min = indexPoints[index] * dir;
  1398. index = ~index & 3;
  1399. dx = -dir.x * cornerVecs[index].x - dir.y * cornerVecs[index].y - dir.z * cornerVecs[index].z;
  1400. index |= ( FLOATSIGNBITSET( dx ) << 2 );
  1401. max = indexPoints[index] * dir;
  1402. }
  1403. /*
  1404. ============
  1405. idFrustum::AxisProjection
  1406. 40 muls
  1407. ============
  1408. */
  1409. void idFrustum::AxisProjection( const idVec3 &dir, float &min, float &max ) const {
  1410. idVec3 indexPoints[8], cornerVecs[4];
  1411. ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  1412. AxisProjection( indexPoints, cornerVecs, dir, min, max );
  1413. }
  1414. /*
  1415. ============
  1416. idFrustum::AxisProjection
  1417. 76 muls
  1418. ============
  1419. */
  1420. void idFrustum::AxisProjection( const idMat3 &ax, idBounds &bounds ) const {
  1421. idVec3 indexPoints[8], cornerVecs[4];
  1422. ToIndexPointsAndCornerVecs( indexPoints, cornerVecs );
  1423. AxisProjection( indexPoints, cornerVecs, ax[0], bounds[0][0], bounds[1][0] );
  1424. AxisProjection( indexPoints, cornerVecs, ax[1], bounds[0][1], bounds[1][1] );
  1425. AxisProjection( indexPoints, cornerVecs, ax[2], bounds[0][2], bounds[1][2] );
  1426. }
  1427. /*
  1428. ============
  1429. idFrustum::AddLocalLineToProjectionBoundsSetCull
  1430. ============
  1431. */
  1432. void idFrustum::AddLocalLineToProjectionBoundsSetCull( const idVec3 &start, const idVec3 &end, int &startCull, int &endCull, idBounds &bounds ) const {
  1433. idVec3 dir, p;
  1434. float d1, d2, fstart, fend, lstart, lend, f;
  1435. float leftScale, upScale;
  1436. int cull1, cull2;
  1437. #ifdef FRUSTUM_DEBUG
  1438. static idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
  1439. if ( r_showInteractionScissors.GetInteger() > 1 ) {
  1440. session->rw->DebugLine( colorGreen, origin + start * axis, origin + end * axis );
  1441. }
  1442. #endif
  1443. leftScale = dLeft * invFar;
  1444. upScale = dUp * invFar;
  1445. dir = end - start;
  1446. fstart = dFar * start.y;
  1447. fend = dFar * end.y;
  1448. lstart = dLeft * start.x;
  1449. lend = dLeft * end.x;
  1450. // test left plane
  1451. d1 = -fstart + lstart;
  1452. d2 = -fend + lend;
  1453. cull1 = FLOATSIGNBITSET( d1 );
  1454. cull2 = FLOATSIGNBITSET( d2 );
  1455. if ( FLOATNOTZERO( d1 ) ) {
  1456. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1457. f = d1 / ( d1 - d2 );
  1458. p.x = start.x + f * dir.x;
  1459. if ( p.x > 0.0f ) {
  1460. p.z = start.z + f * dir.z;
  1461. if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
  1462. p.y = 1.0f;
  1463. p.z = p.z * dFar / ( p.x * dUp );
  1464. bounds.AddPoint( p );
  1465. }
  1466. }
  1467. }
  1468. }
  1469. // test right plane
  1470. d1 = fstart + lstart;
  1471. d2 = fend + lend;
  1472. cull1 |= FLOATSIGNBITSET( d1 ) << 1;
  1473. cull2 |= FLOATSIGNBITSET( d2 ) << 1;
  1474. if ( FLOATNOTZERO( d1 ) ) {
  1475. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1476. f = d1 / ( d1 - d2 );
  1477. p.x = start.x + f * dir.x;
  1478. if ( p.x > 0.0f ) {
  1479. p.z = start.z + f * dir.z;
  1480. if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
  1481. p.y = -1.0f;
  1482. p.z = p.z * dFar / ( p.x * dUp );
  1483. bounds.AddPoint( p );
  1484. }
  1485. }
  1486. }
  1487. }
  1488. fstart = dFar * start.z;
  1489. fend = dFar * end.z;
  1490. lstart = dUp * start.x;
  1491. lend = dUp * end.x;
  1492. // test up plane
  1493. d1 = -fstart + lstart;
  1494. d2 = -fend + lend;
  1495. cull1 |= FLOATSIGNBITSET( d1 ) << 2;
  1496. cull2 |= FLOATSIGNBITSET( d2 ) << 2;
  1497. if ( FLOATNOTZERO( d1 ) ) {
  1498. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1499. f = d1 / ( d1 - d2 );
  1500. p.x = start.x + f * dir.x;
  1501. if ( p.x > 0.0f ) {
  1502. p.y = start.y + f * dir.y;
  1503. if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
  1504. p.y = p.y * dFar / ( p.x * dLeft );
  1505. p.z = 1.0f;
  1506. bounds.AddPoint( p );
  1507. }
  1508. }
  1509. }
  1510. }
  1511. // test down plane
  1512. d1 = fstart + lstart;
  1513. d2 = fend + lend;
  1514. cull1 |= FLOATSIGNBITSET( d1 ) << 3;
  1515. cull2 |= FLOATSIGNBITSET( d2 ) << 3;
  1516. if ( FLOATNOTZERO( d1 ) ) {
  1517. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1518. f = d1 / ( d1 - d2 );
  1519. p.x = start.x + f * dir.x;
  1520. if ( p.x > 0.0f ) {
  1521. p.y = start.y + f * dir.y;
  1522. if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
  1523. p.y = p.y * dFar / ( p.x * dLeft );
  1524. p.z = -1.0f;
  1525. bounds.AddPoint( p );
  1526. }
  1527. }
  1528. }
  1529. }
  1530. if ( cull1 == 0 && start.x > 0.0f ) {
  1531. // add start point to projection bounds
  1532. p.x = start.x;
  1533. p.y = start.y * dFar / ( start.x * dLeft );
  1534. p.z = start.z * dFar / ( start.x * dUp );
  1535. bounds.AddPoint( p );
  1536. }
  1537. if ( cull2 == 0 && end.x > 0.0f ) {
  1538. // add end point to projection bounds
  1539. p.x = end.x;
  1540. p.y = end.y * dFar / ( end.x * dLeft );
  1541. p.z = end.z * dFar / ( end.x * dUp );
  1542. bounds.AddPoint( p );
  1543. }
  1544. if ( start.x < bounds[0].x ) {
  1545. bounds[0].x = start.x < 0.0f ? 0.0f : start.x;
  1546. }
  1547. if ( end.x < bounds[0].x ) {
  1548. bounds[0].x = end.x < 0.0f ? 0.0f : end.x;
  1549. }
  1550. startCull = cull1;
  1551. endCull = cull2;
  1552. }
  1553. /*
  1554. ============
  1555. idFrustum::AddLocalLineToProjectionBoundsUseCull
  1556. ============
  1557. */
  1558. void idFrustum::AddLocalLineToProjectionBoundsUseCull( const idVec3 &start, const idVec3 &end, int startCull, int endCull, idBounds &bounds ) const {
  1559. idVec3 dir, p;
  1560. float d1, d2, fstart, fend, lstart, lend, f;
  1561. float leftScale, upScale;
  1562. int clip;
  1563. clip = startCull ^ endCull;
  1564. if ( !clip ) {
  1565. return;
  1566. }
  1567. #ifdef FRUSTUM_DEBUG
  1568. static idCVar r_showInteractionScissors( "r_showInteractionScissors", "0", CVAR_RENDERER | CVAR_INTEGER, "", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
  1569. if ( r_showInteractionScissors.GetInteger() > 1 ) {
  1570. session->rw->DebugLine( colorGreen, origin + start * axis, origin + end * axis );
  1571. }
  1572. #endif
  1573. leftScale = dLeft * invFar;
  1574. upScale = dUp * invFar;
  1575. dir = end - start;
  1576. if ( clip & (1|2) ) {
  1577. fstart = dFar * start.y;
  1578. fend = dFar * end.y;
  1579. lstart = dLeft * start.x;
  1580. lend = dLeft * end.x;
  1581. if ( clip & 1 ) {
  1582. // test left plane
  1583. d1 = -fstart + lstart;
  1584. d2 = -fend + lend;
  1585. if ( FLOATNOTZERO( d1 ) ) {
  1586. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1587. f = d1 / ( d1 - d2 );
  1588. p.x = start.x + f * dir.x;
  1589. if ( p.x > 0.0f ) {
  1590. p.z = start.z + f * dir.z;
  1591. if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
  1592. p.y = 1.0f;
  1593. p.z = p.z * dFar / ( p.x * dUp );
  1594. bounds.AddPoint( p );
  1595. }
  1596. }
  1597. }
  1598. }
  1599. }
  1600. if ( clip & 2 ) {
  1601. // test right plane
  1602. d1 = fstart + lstart;
  1603. d2 = fend + lend;
  1604. if ( FLOATNOTZERO( d1 ) ) {
  1605. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1606. f = d1 / ( d1 - d2 );
  1607. p.x = start.x + f * dir.x;
  1608. if ( p.x > 0.0f ) {
  1609. p.z = start.z + f * dir.z;
  1610. if ( idMath::Fabs( p.z ) <= p.x * upScale ) {
  1611. p.y = -1.0f;
  1612. p.z = p.z * dFar / ( p.x * dUp );
  1613. bounds.AddPoint( p );
  1614. }
  1615. }
  1616. }
  1617. }
  1618. }
  1619. }
  1620. if ( clip & (4|8) ) {
  1621. fstart = dFar * start.z;
  1622. fend = dFar * end.z;
  1623. lstart = dUp * start.x;
  1624. lend = dUp * end.x;
  1625. if ( clip & 4 ) {
  1626. // test up plane
  1627. d1 = -fstart + lstart;
  1628. d2 = -fend + lend;
  1629. if ( FLOATNOTZERO( d1 ) ) {
  1630. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1631. f = d1 / ( d1 - d2 );
  1632. p.x = start.x + f * dir.x;
  1633. if ( p.x > 0.0f ) {
  1634. p.y = start.y + f * dir.y;
  1635. if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
  1636. p.y = p.y * dFar / ( p.x * dLeft );
  1637. p.z = 1.0f;
  1638. bounds.AddPoint( p );
  1639. }
  1640. }
  1641. }
  1642. }
  1643. }
  1644. if ( clip & 8 ) {
  1645. // test down plane
  1646. d1 = fstart + lstart;
  1647. d2 = fend + lend;
  1648. if ( FLOATNOTZERO( d1 ) ) {
  1649. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  1650. f = d1 / ( d1 - d2 );
  1651. p.x = start.x + f * dir.x;
  1652. if ( p.x > 0.0f ) {
  1653. p.y = start.y + f * dir.y;
  1654. if ( idMath::Fabs( p.y ) <= p.x * leftScale ) {
  1655. p.y = p.y * dFar / ( p.x * dLeft );
  1656. p.z = -1.0f;
  1657. bounds.AddPoint( p );
  1658. }
  1659. }
  1660. }
  1661. }
  1662. }
  1663. }
  1664. }
  1665. /*
  1666. ============
  1667. idFrustum::BoundsRayIntersection
  1668. Returns true if the ray starts inside the bounds.
  1669. If there was an intersection scale1 <= scale2
  1670. ============
  1671. */
  1672. bool idFrustum::BoundsRayIntersection( const idBounds &bounds, const idVec3 &start, const idVec3 &dir, float &scale1, float &scale2 ) const {
  1673. idVec3 end, p;
  1674. float d1, d2, f;
  1675. int i, startInside = 1;
  1676. scale1 = idMath::INFINITY;
  1677. scale2 = -idMath::INFINITY;
  1678. end = start + dir;
  1679. for ( i = 0; i < 2; i++ ) {
  1680. d1 = start.x - bounds[i].x;
  1681. startInside &= FLOATSIGNBITSET( d1 ) ^ i;
  1682. d2 = end.x - bounds[i].x;
  1683. if ( d1 != d2 ) {
  1684. f = d1 / ( d1 - d2 );
  1685. p.y = start.y + f * dir.y;
  1686. if ( bounds[0].y <= p.y && p.y <= bounds[1].y ) {
  1687. p.z = start.z + f * dir.z;
  1688. if ( bounds[0].z <= p.z && p.z <= bounds[1].z ) {
  1689. if ( f < scale1 ) scale1 = f;
  1690. if ( f > scale2 ) scale2 = f;
  1691. }
  1692. }
  1693. }
  1694. d1 = start.y - bounds[i].y;
  1695. startInside &= FLOATSIGNBITSET( d1 ) ^ i;
  1696. d2 = end.y - bounds[i].y;
  1697. if ( d1 != d2 ) {
  1698. f = d1 / ( d1 - d2 );
  1699. p.x = start.x + f * dir.x;
  1700. if ( bounds[0].x <= p.x && p.x <= bounds[1].x ) {
  1701. p.z = start.z + f * dir.z;
  1702. if ( bounds[0].z <= p.z && p.z <= bounds[1].z ) {
  1703. if ( f < scale1 ) scale1 = f;
  1704. if ( f > scale2 ) scale2 = f;
  1705. }
  1706. }
  1707. }
  1708. d1 = start.z - bounds[i].z;
  1709. startInside &= FLOATSIGNBITSET( d1 ) ^ i;
  1710. d2 = end.z - bounds[i].z;
  1711. if ( d1 != d2 ) {
  1712. f = d1 / ( d1 - d2 );
  1713. p.x = start.x + f * dir.x;
  1714. if ( bounds[0].x <= p.x && p.x <= bounds[1].x ) {
  1715. p.y = start.y + f * dir.y;
  1716. if ( bounds[0].y <= p.y && p.y <= bounds[1].y ) {
  1717. if ( f < scale1 ) scale1 = f;
  1718. if ( f > scale2 ) scale2 = f;
  1719. }
  1720. }
  1721. }
  1722. }
  1723. return ( startInside != 0 );
  1724. }
  1725. /*
  1726. ============
  1727. idFrustum::ProjectionBounds
  1728. ============
  1729. */
  1730. bool idFrustum::ProjectionBounds( const idBounds &bounds, idBounds &projectionBounds ) const {
  1731. return ProjectionBounds( idBox( bounds, vec3_origin, mat3_identity ), projectionBounds );
  1732. }
  1733. #ifndef __linux__
  1734. /*
  1735. ============
  1736. idFrustum::ProjectionBounds
  1737. ============
  1738. */
  1739. bool idFrustum::ProjectionBounds( const idBox &box, idBounds &projectionBounds ) const {
  1740. int i, p1, p2, pointCull[8], culled, outside;
  1741. float scale1, scale2;
  1742. idFrustum localFrustum;
  1743. idVec3 points[8], localOrigin;
  1744. idMat3 localAxis, localScaled;
  1745. idBounds bounds( -box.GetExtents(), box.GetExtents() );
  1746. // if the frustum origin is inside the bounds
  1747. if ( bounds.ContainsPoint( ( origin - box.GetCenter() ) * box.GetAxis().Transpose() ) ) {
  1748. // bounds that cover the whole frustum
  1749. float boxMin, boxMax, base;
  1750. base = origin * axis[0];
  1751. box.AxisProjection( axis[0], boxMin, boxMax );
  1752. projectionBounds[0].x = boxMin - base;
  1753. projectionBounds[1].x = boxMax - base;
  1754. projectionBounds[0].y = projectionBounds[0].z = -1.0f;
  1755. projectionBounds[1].y = projectionBounds[1].z = 1.0f;
  1756. return true;
  1757. }
  1758. projectionBounds.Clear();
  1759. // transform the bounds into the space of this frustum
  1760. localOrigin = ( box.GetCenter() - origin ) * axis.Transpose();
  1761. localAxis = box.GetAxis() * axis.Transpose();
  1762. BoxToPoints( localOrigin, box.GetExtents(), localAxis, points );
  1763. // test outer four edges of the bounds
  1764. culled = -1;
  1765. outside = 0;
  1766. for ( i = 0; i < 4; i++ ) {
  1767. p1 = i;
  1768. p2 = 4 + i;
  1769. AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1770. culled &= pointCull[p1] & pointCull[p2];
  1771. outside |= pointCull[p1] | pointCull[p2];
  1772. }
  1773. // if the bounds are completely outside this frustum
  1774. if ( culled ) {
  1775. return false;
  1776. }
  1777. // if the bounds are completely inside this frustum
  1778. if ( !outside ) {
  1779. return true;
  1780. }
  1781. // test the remaining edges of the bounds
  1782. for ( i = 0; i < 4; i++ ) {
  1783. p1 = i;
  1784. p2 = (i+1)&3;
  1785. AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1786. }
  1787. for ( i = 0; i < 4; i++ ) {
  1788. p1 = 4 + i;
  1789. p2 = 4 + ((i+1)&3);
  1790. AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1791. }
  1792. // if the bounds extend beyond two or more boundaries of this frustum
  1793. if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
  1794. localOrigin = ( origin - box.GetCenter() ) * box.GetAxis().Transpose();
  1795. localScaled = axis * box.GetAxis().Transpose();
  1796. localScaled[0] *= dFar;
  1797. localScaled[1] *= dLeft;
  1798. localScaled[2] *= dUp;
  1799. // test the outer edges of this frustum for intersection with the bounds
  1800. if ( (outside & 2) && (outside & 8) ) {
  1801. BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
  1802. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1803. projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
  1804. projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
  1805. }
  1806. }
  1807. if ( (outside & 2) && (outside & 4) ) {
  1808. BoundsRayIntersection( bounds, localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
  1809. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1810. projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
  1811. projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
  1812. }
  1813. }
  1814. if ( (outside & 1) && (outside & 8) ) {
  1815. BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
  1816. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1817. projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
  1818. projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
  1819. }
  1820. }
  1821. if ( (outside & 1) && (outside & 2) ) {
  1822. BoundsRayIntersection( bounds, localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
  1823. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1824. projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
  1825. projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
  1826. }
  1827. }
  1828. }
  1829. return true;
  1830. }
  1831. #endif
  1832. /*
  1833. ============
  1834. idFrustum::ProjectionBounds
  1835. ============
  1836. */
  1837. bool idFrustum::ProjectionBounds( const idSphere &sphere, idBounds &projectionBounds ) const {
  1838. float d, r, rs, sFar;
  1839. idVec3 center;
  1840. projectionBounds.Clear();
  1841. center = ( sphere.GetOrigin() - origin ) * axis.Transpose();
  1842. r = sphere.GetRadius();
  1843. rs = r * r;
  1844. sFar = dFar * dFar;
  1845. // test left/right planes
  1846. d = dFar * idMath::Fabs( center.y ) - dLeft * center.x;
  1847. if ( ( d * d ) > rs * ( sFar + dLeft * dLeft ) ) {
  1848. return false;
  1849. }
  1850. // test up/down planes
  1851. d = dFar * idMath::Fabs( center.z ) - dUp * center.x;
  1852. if ( ( d * d ) > rs * ( sFar + dUp * dUp ) ) {
  1853. return false;
  1854. }
  1855. // bounds that cover the whole frustum
  1856. projectionBounds[0].x = 0.0f;
  1857. projectionBounds[1].x = dFar;
  1858. projectionBounds[0].y = projectionBounds[0].z = -1.0f;
  1859. projectionBounds[1].y = projectionBounds[1].z = 1.0f;
  1860. return true;
  1861. }
  1862. /*
  1863. ============
  1864. idFrustum::ProjectionBounds
  1865. ============
  1866. */
  1867. bool idFrustum::ProjectionBounds( const idFrustum &frustum, idBounds &projectionBounds ) const {
  1868. int i, p1, p2, pointCull[8], culled, outside;
  1869. float scale1, scale2;
  1870. idFrustum localFrustum;
  1871. idVec3 points[8], localOrigin;
  1872. idMat3 localScaled;
  1873. // if the frustum origin is inside the other frustum
  1874. if ( frustum.ContainsPoint( origin ) ) {
  1875. // bounds that cover the whole frustum
  1876. float frustumMin, frustumMax, base;
  1877. base = origin * axis[0];
  1878. frustum.AxisProjection( axis[0], frustumMin, frustumMax );
  1879. projectionBounds[0].x = frustumMin - base;
  1880. projectionBounds[1].x = frustumMax - base;
  1881. projectionBounds[0].y = projectionBounds[0].z = -1.0f;
  1882. projectionBounds[1].y = projectionBounds[1].z = 1.0f;
  1883. return true;
  1884. }
  1885. projectionBounds.Clear();
  1886. // transform the given frustum into the space of this frustum
  1887. localFrustum = frustum;
  1888. localFrustum.origin = ( frustum.origin - origin ) * axis.Transpose();
  1889. localFrustum.axis = frustum.axis * axis.Transpose();
  1890. localFrustum.ToPoints( points );
  1891. // test outer four edges of the other frustum
  1892. culled = -1;
  1893. outside = 0;
  1894. for ( i = 0; i < 4; i++ ) {
  1895. p1 = i;
  1896. p2 = 4 + i;
  1897. AddLocalLineToProjectionBoundsSetCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1898. culled &= pointCull[p1] & pointCull[p2];
  1899. outside |= pointCull[p1] | pointCull[p2];
  1900. }
  1901. // if the other frustum is completely outside this frustum
  1902. if ( culled ) {
  1903. return false;
  1904. }
  1905. // if the other frustum is completely inside this frustum
  1906. if ( !outside ) {
  1907. return true;
  1908. }
  1909. // test the remaining edges of the other frustum
  1910. if ( localFrustum.dNear > 0.0f ) {
  1911. for ( i = 0; i < 4; i++ ) {
  1912. p1 = i;
  1913. p2 = (i+1)&3;
  1914. AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1915. }
  1916. }
  1917. for ( i = 0; i < 4; i++ ) {
  1918. p1 = 4 + i;
  1919. p2 = 4 + ((i+1)&3);
  1920. AddLocalLineToProjectionBoundsUseCull( points[p1], points[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1921. }
  1922. // if the other frustum extends beyond two or more boundaries of this frustum
  1923. if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
  1924. localOrigin = ( origin - frustum.origin ) * frustum.axis.Transpose();
  1925. localScaled = axis * frustum.axis.Transpose();
  1926. localScaled[0] *= dFar;
  1927. localScaled[1] *= dLeft;
  1928. localScaled[2] *= dUp;
  1929. // test the outer edges of this frustum for intersection with the other frustum
  1930. if ( (outside & 2) && (outside & 8) ) {
  1931. frustum.LocalRayIntersection( localOrigin, localScaled[0] - localScaled[1] - localScaled[2], scale1, scale2 );
  1932. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1933. projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, -1.0f ) );
  1934. projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, -1.0f ) );
  1935. }
  1936. }
  1937. if ( (outside & 2) && (outside & 4) ) {
  1938. frustum.LocalRayIntersection( localOrigin, localScaled[0] - localScaled[1] + localScaled[2], scale1, scale2 );
  1939. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1940. projectionBounds.AddPoint( idVec3( scale1 * dFar, -1.0f, 1.0f ) );
  1941. projectionBounds.AddPoint( idVec3( scale2 * dFar, -1.0f, 1.0f ) );
  1942. }
  1943. }
  1944. if ( (outside & 1) && (outside & 8) ) {
  1945. frustum.LocalRayIntersection( localOrigin, localScaled[0] + localScaled[1] - localScaled[2], scale1, scale2 );
  1946. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1947. projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, -1.0f ) );
  1948. projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, -1.0f ) );
  1949. }
  1950. }
  1951. if ( (outside & 1) && (outside & 2) ) {
  1952. frustum.LocalRayIntersection( localOrigin, localScaled[0] + localScaled[1] + localScaled[2], scale1, scale2 );
  1953. if ( scale1 <= scale2 && scale1 >= 0.0f ) {
  1954. projectionBounds.AddPoint( idVec3( scale1 * dFar, 1.0f, 1.0f ) );
  1955. projectionBounds.AddPoint( idVec3( scale2 * dFar, 1.0f, 1.0f ) );
  1956. }
  1957. }
  1958. }
  1959. return true;
  1960. }
  1961. /*
  1962. ============
  1963. idFrustum::ProjectionBounds
  1964. ============
  1965. */
  1966. bool idFrustum::ProjectionBounds( const idWinding &winding, idBounds &projectionBounds ) const {
  1967. int i, p1, p2, *pointCull, culled, outside;
  1968. float scale;
  1969. idVec3 *localPoints;
  1970. idMat3 transpose, scaled;
  1971. idPlane plane;
  1972. projectionBounds.Clear();
  1973. // transform the winding points into the space of this frustum
  1974. localPoints = (idVec3 *) _alloca16( winding.GetNumPoints() * sizeof( idVec3 ) );
  1975. transpose = axis.Transpose();
  1976. for ( i = 0; i < winding.GetNumPoints(); i++ ) {
  1977. localPoints[i] = ( winding[i].ToVec3() - origin ) * transpose;
  1978. }
  1979. // test the winding edges
  1980. culled = -1;
  1981. outside = 0;
  1982. pointCull = (int *) _alloca16( winding.GetNumPoints() * sizeof( int ) );
  1983. for ( i = 0; i < winding.GetNumPoints(); i += 2 ) {
  1984. p1 = i;
  1985. p2 = (i+1)%winding.GetNumPoints();
  1986. AddLocalLineToProjectionBoundsSetCull( localPoints[p1], localPoints[p2], pointCull[p1], pointCull[p2], projectionBounds );
  1987. culled &= pointCull[p1] & pointCull[p2];
  1988. outside |= pointCull[p1] | pointCull[p2];
  1989. }
  1990. // if completely culled
  1991. if ( culled ) {
  1992. return false;
  1993. }
  1994. // if completely inside
  1995. if ( !outside ) {
  1996. return true;
  1997. }
  1998. // test remaining winding edges
  1999. for ( i = 1; i < winding.GetNumPoints(); i += 2 ) {
  2000. p1 = i;
  2001. p2 = (i+1)%winding.GetNumPoints();
  2002. AddLocalLineToProjectionBoundsUseCull( localPoints[p1], localPoints[p2], pointCull[p1], pointCull[p2], projectionBounds );
  2003. }
  2004. // if the winding extends beyond two or more boundaries of this frustum
  2005. if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
  2006. winding.GetPlane( plane );
  2007. scaled[0] = axis[0] * dFar;
  2008. scaled[1] = axis[1] * dLeft;
  2009. scaled[2] = axis[2] * dUp;
  2010. // test the outer edges of this frustum for intersection with the winding
  2011. if ( (outside & 2) && (outside & 8) ) {
  2012. if ( winding.RayIntersection( plane, origin, scaled[0] - scaled[1] - scaled[2], scale ) ) {
  2013. projectionBounds.AddPoint( idVec3( scale * dFar, -1.0f, -1.0f ) );
  2014. }
  2015. }
  2016. if ( (outside & 2) && (outside & 4) ) {
  2017. if ( winding.RayIntersection( plane, origin, scaled[0] - scaled[1] + scaled[2], scale ) ) {
  2018. projectionBounds.AddPoint( idVec3( scale * dFar, -1.0f, 1.0f ) );
  2019. }
  2020. }
  2021. if ( (outside & 1) && (outside & 8) ) {
  2022. if ( winding.RayIntersection( plane, origin, scaled[0] + scaled[1] - scaled[2], scale ) ) {
  2023. projectionBounds.AddPoint( idVec3( scale * dFar, 1.0f, -1.0f ) );
  2024. }
  2025. }
  2026. if ( (outside & 1) && (outside & 2) ) {
  2027. if ( winding.RayIntersection( plane, origin, scaled[0] + scaled[1] + scaled[2], scale ) ) {
  2028. projectionBounds.AddPoint( idVec3( scale * dFar, 1.0f, 1.0f ) );
  2029. }
  2030. }
  2031. }
  2032. return true;
  2033. }
  2034. /*
  2035. ============
  2036. idFrustum::ClipFrustumToBox
  2037. Clips the frustum far extents to the box.
  2038. ============
  2039. */
  2040. void idFrustum::ClipFrustumToBox( const idBox &box, float clipFractions[4], int clipPlanes[4] ) const {
  2041. int i, index;
  2042. float f, minf;
  2043. idMat3 scaled, localAxis, transpose;
  2044. idVec3 localOrigin, cornerVecs[4];
  2045. idBounds bounds;
  2046. transpose = box.GetAxis();
  2047. transpose.TransposeSelf();
  2048. localOrigin = ( origin - box.GetCenter() ) * transpose;
  2049. localAxis = axis * transpose;
  2050. scaled[0] = localAxis[0] * dFar;
  2051. scaled[1] = localAxis[1] * dLeft;
  2052. scaled[2] = localAxis[2] * dUp;
  2053. cornerVecs[0] = scaled[0] + scaled[1];
  2054. cornerVecs[1] = scaled[0] - scaled[1];
  2055. cornerVecs[2] = cornerVecs[1] - scaled[2];
  2056. cornerVecs[3] = cornerVecs[0] - scaled[2];
  2057. cornerVecs[0] += scaled[2];
  2058. cornerVecs[1] += scaled[2];
  2059. bounds[0] = -box.GetExtents();
  2060. bounds[1] = box.GetExtents();
  2061. minf = ( dNear + 1.0f ) * invFar;
  2062. for ( i = 0; i < 4; i++ ) {
  2063. index = FLOATSIGNBITNOTSET( cornerVecs[i].x );
  2064. f = ( bounds[index].x - localOrigin.x ) / cornerVecs[i].x;
  2065. clipFractions[i] = f;
  2066. clipPlanes[i] = 1 << index;
  2067. index = FLOATSIGNBITNOTSET( cornerVecs[i].y );
  2068. f = ( bounds[index].y - localOrigin.y ) / cornerVecs[i].y;
  2069. if ( f < clipFractions[i] ) {
  2070. clipFractions[i] = f;
  2071. clipPlanes[i] = 4 << index;
  2072. }
  2073. index = FLOATSIGNBITNOTSET( cornerVecs[i].z );
  2074. f = ( bounds[index].z - localOrigin.z ) / cornerVecs[i].z;
  2075. if ( f < clipFractions[i] ) {
  2076. clipFractions[i] = f;
  2077. clipPlanes[i] = 16 << index;
  2078. }
  2079. // make sure the frustum is not clipped between the frustum origin and the near plane
  2080. if ( clipFractions[i] < minf ) {
  2081. clipFractions[i] = minf;
  2082. }
  2083. }
  2084. }
  2085. /*
  2086. ============
  2087. idFrustum::ClipLine
  2088. Returns true if part of the line is inside the frustum.
  2089. Does not clip to the near and far plane.
  2090. ============
  2091. */
  2092. bool idFrustum::ClipLine( const idVec3 localPoints[8], const idVec3 points[8], int startIndex, int endIndex, idVec3 &start, idVec3 &end, int &startClip, int &endClip ) const {
  2093. float d1, d2, fstart, fend, lstart, lend, f, x;
  2094. float leftScale, upScale;
  2095. float scale1, scale2;
  2096. int startCull, endCull;
  2097. idVec3 localStart, localEnd, localDir;
  2098. leftScale = dLeft * invFar;
  2099. upScale = dUp * invFar;
  2100. localStart = localPoints[startIndex];
  2101. localEnd = localPoints[endIndex];
  2102. localDir = localEnd - localStart;
  2103. startClip = endClip = -1;
  2104. scale1 = idMath::INFINITY;
  2105. scale2 = -idMath::INFINITY;
  2106. fstart = dFar * localStart.y;
  2107. fend = dFar * localEnd.y;
  2108. lstart = dLeft * localStart.x;
  2109. lend = dLeft * localEnd.x;
  2110. // test left plane
  2111. d1 = -fstart + lstart;
  2112. d2 = -fend + lend;
  2113. startCull = FLOATSIGNBITSET( d1 );
  2114. endCull = FLOATSIGNBITSET( d2 );
  2115. if ( FLOATNOTZERO( d1 ) ) {
  2116. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  2117. f = d1 / ( d1 - d2 );
  2118. x = localStart.x + f * localDir.x;
  2119. if ( x >= 0.0f ) {
  2120. if ( idMath::Fabs( localStart.z + f * localDir.z ) <= x * upScale ) {
  2121. if ( f < scale1 ) { scale1 = f; startClip = 0; }
  2122. if ( f > scale2 ) { scale2 = f; endClip = 0; }
  2123. }
  2124. }
  2125. }
  2126. }
  2127. // test right plane
  2128. d1 = fstart + lstart;
  2129. d2 = fend + lend;
  2130. startCull |= FLOATSIGNBITSET( d1 ) << 1;
  2131. endCull |= FLOATSIGNBITSET( d2 ) << 1;
  2132. if ( FLOATNOTZERO( d1 ) ) {
  2133. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  2134. f = d1 / ( d1 - d2 );
  2135. x = localStart.x + f * localDir.x;
  2136. if ( x >= 0.0f ) {
  2137. if ( idMath::Fabs( localStart.z + f * localDir.z ) <= x * upScale ) {
  2138. if ( f < scale1 ) { scale1 = f; startClip = 1; }
  2139. if ( f > scale2 ) { scale2 = f; endClip = 1; }
  2140. }
  2141. }
  2142. }
  2143. }
  2144. fstart = dFar * localStart.z;
  2145. fend = dFar * localEnd.z;
  2146. lstart = dUp * localStart.x;
  2147. lend = dUp * localEnd.x;
  2148. // test up plane
  2149. d1 = -fstart + lstart;
  2150. d2 = -fend + lend;
  2151. startCull |= FLOATSIGNBITSET( d1 ) << 2;
  2152. endCull |= FLOATSIGNBITSET( d2 ) << 2;
  2153. if ( FLOATNOTZERO( d1 ) ) {
  2154. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  2155. f = d1 / ( d1 - d2 );
  2156. x = localStart.x + f * localDir.x;
  2157. if ( x >= 0.0f ) {
  2158. if ( idMath::Fabs( localStart.y + f * localDir.y ) <= x * leftScale ) {
  2159. if ( f < scale1 ) { scale1 = f; startClip = 2; }
  2160. if ( f > scale2 ) { scale2 = f; endClip = 2; }
  2161. }
  2162. }
  2163. }
  2164. }
  2165. // test down plane
  2166. d1 = fstart + lstart;
  2167. d2 = fend + lend;
  2168. startCull |= FLOATSIGNBITSET( d1 ) << 3;
  2169. endCull |= FLOATSIGNBITSET( d2 ) << 3;
  2170. if ( FLOATNOTZERO( d1 ) ) {
  2171. if ( FLOATSIGNBITSET( d1 ) ^ FLOATSIGNBITSET( d2 ) ) {
  2172. f = d1 / ( d1 - d2 );
  2173. x = localStart.x + f * localDir.x;
  2174. if ( x >= 0.0f ) {
  2175. if ( idMath::Fabs( localStart.y + f * localDir.y ) <= x * leftScale ) {
  2176. if ( f < scale1 ) { scale1 = f; startClip = 3; }
  2177. if ( f > scale2 ) { scale2 = f; endClip = 3; }
  2178. }
  2179. }
  2180. }
  2181. }
  2182. // if completely inside
  2183. if ( !( startCull | endCull ) ) {
  2184. start = points[startIndex];
  2185. end = points[endIndex];
  2186. return true;
  2187. }
  2188. else if ( scale1 <= scale2 ) {
  2189. if ( !startCull ) {
  2190. start = points[startIndex];
  2191. startClip = -1;
  2192. }
  2193. else {
  2194. start = points[startIndex] + scale1 * ( points[endIndex] - points[startIndex] );
  2195. }
  2196. if ( !endCull ) {
  2197. end = points[endIndex];
  2198. endClip = -1;
  2199. }
  2200. else {
  2201. end = points[startIndex] + scale2 * ( points[endIndex] - points[startIndex] );
  2202. }
  2203. return true;
  2204. }
  2205. return false;
  2206. }
  2207. /*
  2208. ============
  2209. idFrustum::AddLocalCapsToProjectionBounds
  2210. ============
  2211. */
  2212. static int capPointIndex[4][2] = {
  2213. { 0, 3 },
  2214. { 1, 2 },
  2215. { 0, 1 },
  2216. { 2, 3 }
  2217. };
  2218. ID_INLINE bool idFrustum::AddLocalCapsToProjectionBounds( const idVec3 endPoints[4], const int endPointCull[4], const idVec3 &point, int pointCull, int pointClip, idBounds &projectionBounds ) const {
  2219. int *p;
  2220. if ( pointClip < 0 ) {
  2221. return false;
  2222. }
  2223. p = capPointIndex[pointClip];
  2224. AddLocalLineToProjectionBoundsUseCull( endPoints[p[0]], point, endPointCull[p[0]], pointCull, projectionBounds );
  2225. AddLocalLineToProjectionBoundsUseCull( endPoints[p[1]], point, endPointCull[p[1]], pointCull, projectionBounds );
  2226. return true;
  2227. }
  2228. /*
  2229. ============
  2230. idFrustum::ClippedProjectionBounds
  2231. ============
  2232. */
  2233. bool idFrustum::ClippedProjectionBounds( const idFrustum &frustum, const idBox &clipBox, idBounds &projectionBounds ) const {
  2234. int i, p1, p2, clipPointCull[8], clipPlanes[4], usedClipPlanes, nearCull, farCull, outside;
  2235. int pointCull[2], startClip, endClip, boxPointCull[8];
  2236. float clipFractions[4], s1, s2, t1, t2, leftScale, upScale;
  2237. idFrustum localFrustum;
  2238. idVec3 clipPoints[8], localPoints1[8], localPoints2[8], localOrigin1, localOrigin2, start, end;
  2239. idMat3 localAxis1, localAxis2, transpose;
  2240. idBounds clipBounds;
  2241. // if the frustum origin is inside the other frustum
  2242. if ( frustum.ContainsPoint( origin ) ) {
  2243. // bounds that cover the whole frustum
  2244. float clipBoxMin, clipBoxMax, frustumMin, frustumMax, base;
  2245. base = origin * axis[0];
  2246. clipBox.AxisProjection( axis[0], clipBoxMin, clipBoxMax );
  2247. frustum.AxisProjection( axis[0], frustumMin, frustumMax );
  2248. projectionBounds[0].x = Max( clipBoxMin, frustumMin ) - base;
  2249. projectionBounds[1].x = Min( clipBoxMax, frustumMax ) - base;
  2250. projectionBounds[0].y = projectionBounds[0].z = -1.0f;
  2251. projectionBounds[1].y = projectionBounds[1].z = 1.0f;
  2252. return true;
  2253. }
  2254. projectionBounds.Clear();
  2255. // clip the outer edges of the given frustum to the clip bounds
  2256. frustum.ClipFrustumToBox( clipBox, clipFractions, clipPlanes );
  2257. usedClipPlanes = clipPlanes[0] | clipPlanes[1] | clipPlanes[2] | clipPlanes[3];
  2258. // transform the clipped frustum to the space of this frustum
  2259. transpose = axis;
  2260. transpose.TransposeSelf();
  2261. localFrustum = frustum;
  2262. localFrustum.origin = ( frustum.origin - origin ) * transpose;
  2263. localFrustum.axis = frustum.axis * transpose;
  2264. localFrustum.ToClippedPoints( clipFractions, clipPoints );
  2265. // test outer four edges of the clipped frustum
  2266. for ( i = 0; i < 4; i++ ) {
  2267. p1 = i;
  2268. p2 = 4 + i;
  2269. AddLocalLineToProjectionBoundsSetCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
  2270. }
  2271. // get cull bits for the clipped frustum
  2272. outside = clipPointCull[0] | clipPointCull[1] | clipPointCull[2] | clipPointCull[3] |
  2273. clipPointCull[4] | clipPointCull[5] | clipPointCull[6] | clipPointCull[7];
  2274. nearCull = clipPointCull[0] & clipPointCull[1] & clipPointCull[2] & clipPointCull[3];
  2275. farCull = clipPointCull[4] & clipPointCull[5] & clipPointCull[6] & clipPointCull[7];
  2276. // if the clipped frustum is not completely inside this frustum
  2277. if ( outside ) {
  2278. // test the remaining edges of the clipped frustum
  2279. if ( !nearCull && localFrustum.dNear > 0.0f ) {
  2280. for ( i = 0; i < 4; i++ ) {
  2281. p1 = i;
  2282. p2 = (i+1)&3;
  2283. AddLocalLineToProjectionBoundsUseCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
  2284. }
  2285. }
  2286. if ( !farCull ) {
  2287. for ( i = 0; i < 4; i++ ) {
  2288. p1 = 4 + i;
  2289. p2 = 4 + ((i+1)&3);
  2290. AddLocalLineToProjectionBoundsUseCull( clipPoints[p1], clipPoints[p2], clipPointCull[p1], clipPointCull[p2], projectionBounds );
  2291. }
  2292. }
  2293. }
  2294. // if the clipped frustum far end points are inside this frustum
  2295. if ( !( farCull && !( nearCull & farCull ) ) &&
  2296. // if the clipped frustum is not clipped to a single plane of the clip bounds
  2297. ( clipPlanes[0] != clipPlanes[1] || clipPlanes[1] != clipPlanes[2] || clipPlanes[2] != clipPlanes[3] ) ) {
  2298. // transform the clip box into the space of the other frustum
  2299. transpose = frustum.axis;
  2300. transpose.TransposeSelf();
  2301. localOrigin1 = ( clipBox.GetCenter() - frustum.origin ) * transpose;
  2302. localAxis1 = clipBox.GetAxis() * transpose;
  2303. BoxToPoints( localOrigin1, clipBox.GetExtents(), localAxis1, localPoints1 );
  2304. // cull the box corners with the other frustum
  2305. leftScale = frustum.dLeft * frustum.invFar;
  2306. upScale = frustum.dUp * frustum.invFar;
  2307. for ( i = 0; i < 8; i++ ) {
  2308. idVec3 &p = localPoints1[i];
  2309. if ( !( boxVertPlanes[i] & usedClipPlanes ) || p.x <= 0.0f ) {
  2310. boxPointCull[i] = 1|2|4|8;
  2311. }
  2312. else {
  2313. boxPointCull[i] = 0;
  2314. if ( idMath::Fabs( p.y ) > p.x * leftScale ) {
  2315. boxPointCull[i] |= 1 << FLOATSIGNBITSET( p.y );
  2316. }
  2317. if ( idMath::Fabs( p.z ) > p.x * upScale ) {
  2318. boxPointCull[i] |= 4 << FLOATSIGNBITSET( p.z );
  2319. }
  2320. }
  2321. }
  2322. // transform the clip box into the space of this frustum
  2323. transpose = axis;
  2324. transpose.TransposeSelf();
  2325. localOrigin2 = ( clipBox.GetCenter() - origin ) * transpose;
  2326. localAxis2 = clipBox.GetAxis() * transpose;
  2327. BoxToPoints( localOrigin2, clipBox.GetExtents(), localAxis2, localPoints2 );
  2328. // clip the edges of the clip bounds to the other frustum and add the clipped edges to the projection bounds
  2329. for ( i = 0; i < 4; i++ ) {
  2330. p1 = i;
  2331. p2 = 4 + i;
  2332. if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
  2333. if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
  2334. AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
  2335. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
  2336. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
  2337. outside |= pointCull[0] | pointCull[1];
  2338. }
  2339. }
  2340. }
  2341. for ( i = 0; i < 4; i++ ) {
  2342. p1 = i;
  2343. p2 = (i+1)&3;
  2344. if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
  2345. if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
  2346. AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
  2347. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
  2348. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
  2349. outside |= pointCull[0] | pointCull[1];
  2350. }
  2351. }
  2352. }
  2353. for ( i = 0; i < 4; i++ ) {
  2354. p1 = 4 + i;
  2355. p2 = 4 + ((i+1)&3);
  2356. if ( !( boxPointCull[p1] & boxPointCull[p2] ) ) {
  2357. if ( frustum.ClipLine( localPoints1, localPoints2, p1, p2, start, end, startClip, endClip ) ) {
  2358. AddLocalLineToProjectionBoundsSetCull( start, end, pointCull[0], pointCull[1], projectionBounds );
  2359. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, start, pointCull[0], startClip, projectionBounds );
  2360. AddLocalCapsToProjectionBounds( clipPoints+4, clipPointCull+4, end, pointCull[1], endClip, projectionBounds );
  2361. outside |= pointCull[0] | pointCull[1];
  2362. }
  2363. }
  2364. }
  2365. }
  2366. // if the clipped frustum extends beyond two or more boundaries of this frustum
  2367. if ( outside != 1 && outside != 2 && outside != 4 && outside != 8 ) {
  2368. // transform this frustum into the space of the other frustum
  2369. transpose = frustum.axis;
  2370. transpose.TransposeSelf();
  2371. localOrigin1 = ( origin - frustum.origin ) * transpose;
  2372. localAxis1 = axis * transpose;
  2373. localAxis1[0] *= dFar;
  2374. localAxis1[1] *= dLeft;
  2375. localAxis1[2] *= dUp;
  2376. // transform this frustum into the space of the clip bounds
  2377. transpose = clipBox.GetAxis();
  2378. transpose.TransposeSelf();
  2379. localOrigin2 = ( origin - clipBox.GetCenter() ) * transpose;
  2380. localAxis2 = axis * transpose;
  2381. localAxis2[0] *= dFar;
  2382. localAxis2[1] *= dLeft;
  2383. localAxis2[2] *= dUp;
  2384. clipBounds[0] = -clipBox.GetExtents();
  2385. clipBounds[1] = clipBox.GetExtents();
  2386. // test the outer edges of this frustum for intersection with both the other frustum and the clip bounds
  2387. if ( (outside & 2) && (outside & 8) ) {
  2388. frustum.LocalRayIntersection( localOrigin1, localAxis1[0] - localAxis1[1] - localAxis1[2], s1, s2 );
  2389. if ( s1 <= s2 && s1 >= 0.0f ) {
  2390. BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] - localAxis2[1] - localAxis2[2], t1, t2 );
  2391. if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
  2392. projectionBounds.AddPoint( idVec3( s1 * dFar, -1.0f, -1.0f ) );
  2393. projectionBounds.AddPoint( idVec3( s2 * dFar, -1.0f, -1.0f ) );
  2394. }
  2395. }
  2396. }
  2397. if ( (outside & 2) && (outside & 4) ) {
  2398. frustum.LocalRayIntersection( localOrigin1, localAxis1[0] - localAxis1[1] + localAxis1[2], s1, s2 );
  2399. if ( s1 <= s2 && s1 >= 0.0f ) {
  2400. BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] - localAxis2[1] + localAxis2[2], t1, t2 );
  2401. if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
  2402. projectionBounds.AddPoint( idVec3( s1 * dFar, -1.0f, 1.0f ) );
  2403. projectionBounds.AddPoint( idVec3( s2 * dFar, -1.0f, 1.0f ) );
  2404. }
  2405. }
  2406. }
  2407. if ( (outside & 1) && (outside & 8) ) {
  2408. frustum.LocalRayIntersection( localOrigin1, localAxis1[0] + localAxis1[1] - localAxis1[2], s1, s2 );
  2409. if ( s1 <= s2 && s1 >= 0.0f ) {
  2410. BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] + localAxis2[1] - localAxis2[2], t1, t2 );
  2411. if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
  2412. projectionBounds.AddPoint( idVec3( s1 * dFar, 1.0f, -1.0f ) );
  2413. projectionBounds.AddPoint( idVec3( s2 * dFar, 1.0f, -1.0f ) );
  2414. }
  2415. }
  2416. }
  2417. if ( (outside & 1) && (outside & 2) ) {
  2418. frustum.LocalRayIntersection( localOrigin1, localAxis1[0] + localAxis1[1] + localAxis1[2], s1, s2 );
  2419. if ( s1 <= s2 && s1 >= 0.0f ) {
  2420. BoundsRayIntersection( clipBounds, localOrigin2, localAxis2[0] + localAxis2[1] + localAxis2[2], t1, t2 );
  2421. if ( t1 <= t2 && t2 > s1 && t1 < s2 ) {
  2422. projectionBounds.AddPoint( idVec3( s1 * dFar, 1.0f, 1.0f ) );
  2423. projectionBounds.AddPoint( idVec3( s2 * dFar, 1.0f, 1.0f ) );
  2424. }
  2425. }
  2426. }
  2427. }
  2428. return true;
  2429. }