tr_subview.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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 "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "tr_local.h"
  23. typedef struct {
  24. idVec3 origin;
  25. idMat3 axis;
  26. } orientation_t;
  27. /*
  28. =================
  29. R_MirrorPoint
  30. =================
  31. */
  32. static void R_MirrorPoint( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
  33. int i;
  34. idVec3 local;
  35. idVec3 transformed;
  36. float d;
  37. local = in - surface->origin;
  38. transformed = vec3_origin;
  39. for ( i = 0 ; i < 3 ; i++ ) {
  40. d = local * surface->axis[i];
  41. transformed += d * camera->axis[i];
  42. }
  43. out = transformed + camera->origin;
  44. }
  45. /*
  46. =================
  47. R_MirrorVector
  48. =================
  49. */
  50. static void R_MirrorVector( const idVec3 in, orientation_t *surface, orientation_t *camera, idVec3 &out ) {
  51. int i;
  52. float d;
  53. out = vec3_origin;
  54. for ( i = 0 ; i < 3 ; i++ ) {
  55. d = in * surface->axis[i];
  56. out += d * camera->axis[i];
  57. }
  58. }
  59. /*
  60. =============
  61. R_PlaneForSurface
  62. Returns the plane for the first triangle in the surface
  63. FIXME: check for degenerate triangle?
  64. =============
  65. */
  66. static void R_PlaneForSurface( const srfTriangles_t *tri, idPlane &plane ) {
  67. idDrawVert *v1, *v2, *v3;
  68. v1 = tri->verts + tri->indexes[0];
  69. v2 = tri->verts + tri->indexes[1];
  70. v3 = tri->verts + tri->indexes[2];
  71. plane.FromPoints( v1->xyz, v2->xyz, v3->xyz );
  72. }
  73. /*
  74. =========================
  75. R_PreciseCullSurface
  76. Check the surface for visibility on a per-triangle basis
  77. for cases when it is going to be VERY expensive to draw (subviews)
  78. If not culled, also returns the bounding box of the surface in
  79. Normalized Device Coordinates, so it can be used to crop the scissor rect.
  80. OPTIMIZE: we could also take exact portal passing into consideration
  81. =========================
  82. */
  83. bool R_PreciseCullSurface( const drawSurf_t *drawSurf, idBounds &ndcBounds ) {
  84. const srfTriangles_t *tri;
  85. int numTriangles;
  86. idPlane clip, eye;
  87. int i, j;
  88. unsigned int pointOr;
  89. unsigned int pointAnd;
  90. idVec3 localView;
  91. idFixedWinding w;
  92. tri = drawSurf->geo;
  93. pointOr = 0;
  94. pointAnd = (unsigned int)~0;
  95. // get an exact bounds of the triangles for scissor cropping
  96. ndcBounds.Clear();
  97. for ( i = 0; i < tri->numVerts; i++ ) {
  98. int j;
  99. unsigned int pointFlags;
  100. R_TransformModelToClip( tri->verts[i].xyz, drawSurf->space->modelViewMatrix,
  101. tr.viewDef->projectionMatrix, eye, clip );
  102. pointFlags = 0;
  103. for ( j = 0; j < 3; j++ ) {
  104. if ( clip[j] >= clip[3] ) {
  105. pointFlags |= (1 << (j*2));
  106. } else if ( clip[j] <= -clip[3] ) {
  107. pointFlags |= ( 1 << (j*2+1));
  108. }
  109. }
  110. pointAnd &= pointFlags;
  111. pointOr |= pointFlags;
  112. }
  113. // trivially reject
  114. if ( pointAnd ) {
  115. return true;
  116. }
  117. // backface and frustum cull
  118. numTriangles = tri->numIndexes / 3;
  119. R_GlobalPointToLocal( drawSurf->space->modelMatrix, tr.viewDef->renderView.vieworg, localView );
  120. for ( i = 0; i < tri->numIndexes; i += 3 ) {
  121. idVec3 dir, normal;
  122. float dot;
  123. idVec3 d1, d2;
  124. const idVec3 &v1 = tri->verts[tri->indexes[i]].xyz;
  125. const idVec3 &v2 = tri->verts[tri->indexes[i+1]].xyz;
  126. const idVec3 &v3 = tri->verts[tri->indexes[i+2]].xyz;
  127. // this is a hack, because R_GlobalPointToLocal doesn't work with the non-normalized
  128. // axis that we get from the gui view transform. It doesn't hurt anything, because
  129. // we know that all gui generated surfaces are front facing
  130. if ( tr.guiRecursionLevel == 0 ) {
  131. // we don't care that it isn't normalized,
  132. // all we want is the sign
  133. d1 = v2 - v1;
  134. d2 = v3 - v1;
  135. normal = d2.Cross( d1 );
  136. dir = v1 - localView;
  137. dot = normal * dir;
  138. if ( dot >= 0.0f ) {
  139. return true;
  140. }
  141. }
  142. // now find the exact screen bounds of the clipped triangle
  143. w.SetNumPoints( 3 );
  144. R_LocalPointToGlobal( drawSurf->space->modelMatrix, v1, w[0].ToVec3() );
  145. R_LocalPointToGlobal( drawSurf->space->modelMatrix, v2, w[1].ToVec3() );
  146. R_LocalPointToGlobal( drawSurf->space->modelMatrix, v3, w[2].ToVec3() );
  147. w[0].s = w[0].t = w[1].s = w[1].t = w[2].s = w[2].t = 0.0f;
  148. for ( j = 0; j < 4; j++ ) {
  149. if ( !w.ClipInPlace( -tr.viewDef->frustum[j], 0.1f ) ) {
  150. break;
  151. }
  152. }
  153. for ( j = 0; j < w.GetNumPoints(); j++ ) {
  154. idVec3 screen;
  155. R_GlobalToNormalizedDeviceCoordinates( w[j].ToVec3(), screen );
  156. ndcBounds.AddPoint( screen );
  157. }
  158. }
  159. // if we don't enclose any area, return
  160. if ( ndcBounds.IsCleared() ) {
  161. return true;
  162. }
  163. return false;
  164. }
  165. /*
  166. ========================
  167. R_MirrorViewBySurface
  168. ========================
  169. */
  170. static viewDef_t *R_MirrorViewBySurface( drawSurf_t *drawSurf ) {
  171. viewDef_t *parms;
  172. orientation_t surface, camera;
  173. idPlane originalPlane, plane;
  174. // copy the viewport size from the original
  175. parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
  176. *parms = *tr.viewDef;
  177. parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
  178. parms->isSubview = true;
  179. parms->isMirror = true;
  180. // create plane axis for the portal we are seeing
  181. R_PlaneForSurface( drawSurf->geo, originalPlane );
  182. R_LocalPlaneToGlobal( drawSurf->space->modelMatrix, originalPlane, plane );
  183. surface.origin = plane.Normal() * -plane[3];
  184. surface.axis[0] = plane.Normal();
  185. surface.axis[0].NormalVectors( surface.axis[1], surface.axis[2] );
  186. surface.axis[2] = -surface.axis[2];
  187. camera.origin = surface.origin;
  188. camera.axis[0] = -surface.axis[0];
  189. camera.axis[1] = surface.axis[1];
  190. camera.axis[2] = surface.axis[2];
  191. // set the mirrored origin and axis
  192. R_MirrorPoint( tr.viewDef->renderView.vieworg, &surface, &camera, parms->renderView.vieworg );
  193. R_MirrorVector( tr.viewDef->renderView.viewaxis[0], &surface, &camera, parms->renderView.viewaxis[0] );
  194. R_MirrorVector( tr.viewDef->renderView.viewaxis[1], &surface, &camera, parms->renderView.viewaxis[1] );
  195. R_MirrorVector( tr.viewDef->renderView.viewaxis[2], &surface, &camera, parms->renderView.viewaxis[2] );
  196. // make the view origin 16 units away from the center of the surface
  197. idVec3 viewOrigin = ( drawSurf->geo->bounds[0] + drawSurf->geo->bounds[1] ) * 0.5;
  198. viewOrigin += ( originalPlane.Normal() * 16 );
  199. R_LocalPointToGlobal( drawSurf->space->modelMatrix, viewOrigin, parms->initialViewAreaOrigin );
  200. // set the mirror clip plane
  201. parms->numClipPlanes = 1;
  202. parms->clipPlanes[0] = -camera.axis[0];
  203. parms->clipPlanes[0][3] = -( camera.origin * parms->clipPlanes[0].Normal() );
  204. return parms;
  205. }
  206. /*
  207. ========================
  208. R_XrayViewBySurface
  209. ========================
  210. */
  211. static viewDef_t *R_XrayViewBySurface( drawSurf_t *drawSurf ) {
  212. viewDef_t *parms;
  213. orientation_t surface, camera;
  214. idPlane originalPlane, plane;
  215. // copy the viewport size from the original
  216. parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
  217. *parms = *tr.viewDef;
  218. parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
  219. parms->isSubview = true;
  220. parms->isXraySubview = true;
  221. return parms;
  222. }
  223. /*
  224. ===============
  225. R_RemoteRender
  226. ===============
  227. */
  228. static void R_RemoteRender( drawSurf_t *surf, textureStage_t *stage ) {
  229. viewDef_t *parms;
  230. // remote views can be reused in a single frame
  231. if ( stage->dynamicFrameCount == tr.frameCount ) {
  232. return;
  233. }
  234. // if the entity doesn't have a remoteRenderView, do nothing
  235. if ( !surf->space->entityDef->parms.remoteRenderView ) {
  236. return;
  237. }
  238. if (surf->space->entityDef->parms.isFreezeFrame >= 2)
  239. return;
  240. if (surf->space->entityDef->parms.isFreezeFrame == 1)
  241. surf->space->entityDef->parms.isFreezeFrame = 2;
  242. // copy the viewport size from the original
  243. parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) );
  244. *parms = *tr.viewDef;
  245. parms->isSubview = true;
  246. parms->isMirror = false;
  247. parms->renderView = *surf->space->entityDef->parms.remoteRenderView;
  248. parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons
  249. parms->initialViewAreaOrigin = parms->renderView.vieworg;
  250. tr.CropRenderSize( stage->width, stage->height, true );
  251. parms->renderView.x = 0;
  252. parms->renderView.y = 0;
  253. parms->renderView.width = SCREEN_WIDTH;
  254. parms->renderView.height = SCREEN_HEIGHT;
  255. tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
  256. parms->scissor.x1 = 0;
  257. parms->scissor.y1 = 0;
  258. parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
  259. parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
  260. parms->superView = tr.viewDef;
  261. parms->subviewSurface = surf;
  262. // generate render commands for it
  263. R_RenderView(parms);
  264. // copy this rendering to the image
  265. stage->dynamicFrameCount = tr.frameCount;
  266. if (!stage->image) {
  267. stage->image = globalImages->scratchImage;
  268. }
  269. tr.CaptureRenderToImage( stage->image->imgName );
  270. tr.UnCrop();
  271. }
  272. /*
  273. =================
  274. R_MirrorRender
  275. =================
  276. */
  277. void R_MirrorRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
  278. viewDef_t *parms;
  279. // remote views can be reused in a single frame
  280. if ( stage->dynamicFrameCount == tr.frameCount ) {
  281. return;
  282. }
  283. // issue a new view command
  284. parms = R_MirrorViewBySurface( surf );
  285. if ( !parms ) {
  286. return;
  287. }
  288. tr.CropRenderSize( stage->width, stage->height, true );
  289. parms->renderView.x = 0;
  290. parms->renderView.y = 0;
  291. parms->renderView.width = SCREEN_WIDTH;
  292. parms->renderView.height = SCREEN_HEIGHT;
  293. tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
  294. parms->scissor.x1 = 0;
  295. parms->scissor.y1 = 0;
  296. parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
  297. parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
  298. parms->superView = tr.viewDef;
  299. parms->subviewSurface = surf;
  300. // triangle culling order changes with mirroring
  301. parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
  302. // generate render commands for it
  303. R_RenderView( parms );
  304. // copy this rendering to the image
  305. stage->dynamicFrameCount = tr.frameCount;
  306. stage->image = globalImages->scratchImage;
  307. tr.CaptureRenderToImage( stage->image->imgName );
  308. tr.UnCrop();
  309. }
  310. /*
  311. =================
  312. R_XrayRender
  313. =================
  314. */
  315. void R_XrayRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) {
  316. viewDef_t *parms;
  317. // remote views can be reused in a single frame
  318. if ( stage->dynamicFrameCount == tr.frameCount ) {
  319. return;
  320. }
  321. // issue a new view command
  322. parms = R_XrayViewBySurface( surf );
  323. if ( !parms ) {
  324. return;
  325. }
  326. tr.CropRenderSize( stage->width, stage->height, true );
  327. parms->renderView.x = 0;
  328. parms->renderView.y = 0;
  329. parms->renderView.width = SCREEN_WIDTH;
  330. parms->renderView.height = SCREEN_HEIGHT;
  331. tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
  332. parms->scissor.x1 = 0;
  333. parms->scissor.y1 = 0;
  334. parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
  335. parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
  336. parms->superView = tr.viewDef;
  337. parms->subviewSurface = surf;
  338. // triangle culling order changes with mirroring
  339. parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
  340. // generate render commands for it
  341. R_RenderView( parms );
  342. // copy this rendering to the image
  343. stage->dynamicFrameCount = tr.frameCount;
  344. stage->image = globalImages->scratchImage2;
  345. tr.CaptureRenderToImage( stage->image->imgName );
  346. tr.UnCrop();
  347. }
  348. /*
  349. ==================
  350. R_GenerateSurfaceSubview
  351. ==================
  352. */
  353. bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) {
  354. idBounds ndcBounds;
  355. viewDef_t *parms;
  356. const idMaterial *shader;
  357. // for testing the performance hit
  358. if ( r_skipSubviews.GetBool() ) {
  359. return false;
  360. }
  361. if ( R_PreciseCullSurface( drawSurf, ndcBounds ) ) {
  362. return false;
  363. }
  364. shader = drawSurf->material;
  365. // never recurse through a subview surface that we are
  366. // already seeing through
  367. for ( parms = tr.viewDef ; parms ; parms = parms->superView ) {
  368. if ( parms->subviewSurface
  369. && parms->subviewSurface->geo == drawSurf->geo
  370. && parms->subviewSurface->space->entityDef == drawSurf->space->entityDef ) {
  371. break;
  372. }
  373. }
  374. if ( parms ) {
  375. return false;
  376. }
  377. // crop the scissor bounds based on the precise cull
  378. idScreenRect scissor;
  379. idScreenRect *v = &tr.viewDef->viewport;
  380. scissor.x1 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f ));
  381. scissor.y1 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f ));
  382. scissor.x2 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f ));
  383. scissor.y2 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f ));
  384. // nudge a bit for safety
  385. scissor.Expand();
  386. scissor.Intersect( tr.viewDef->scissor );
  387. if ( scissor.IsEmpty() ) {
  388. // cropped out
  389. return false;
  390. }
  391. // see what kind of subview we are making
  392. if ( shader->GetSort() != SS_SUBVIEW ) {
  393. for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) {
  394. const shaderStage_t *stage = shader->GetStage( i );
  395. switch ( stage->texture.dynamic ) {
  396. case DI_REMOTE_RENDER:
  397. R_RemoteRender( drawSurf, const_cast<textureStage_t *>(&stage->texture) );
  398. break;
  399. case DI_MIRROR_RENDER:
  400. R_MirrorRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
  401. break;
  402. case DI_XRAY_RENDER:
  403. R_XrayRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor );
  404. break;
  405. }
  406. }
  407. return true;
  408. }
  409. // issue a new view command
  410. parms = R_MirrorViewBySurface( drawSurf );
  411. if ( !parms ) {
  412. return false;
  413. }
  414. parms->scissor = scissor;
  415. parms->superView = tr.viewDef;
  416. parms->subviewSurface = drawSurf;
  417. // triangle culling order changes with mirroring
  418. parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 );
  419. // generate render commands for it
  420. R_RenderView( parms );
  421. return true;
  422. }
  423. /*
  424. ================
  425. R_GenerateSubViews
  426. If we need to render another view to complete the current view,
  427. generate it first.
  428. It is important to do this after all drawSurfs for the current
  429. view have been generated, because it may create a subview which
  430. would change tr.viewCount.
  431. ================
  432. */
  433. bool R_GenerateSubViews( void ) {
  434. drawSurf_t *drawSurf;
  435. int i;
  436. bool subviews;
  437. const idMaterial *shader;
  438. // for testing the performance hit
  439. if ( r_skipSubviews.GetBool() ) {
  440. return false;
  441. }
  442. subviews = false;
  443. // scan the surfaces until we either find a subview, or determine
  444. // there are no more subview surfaces.
  445. for ( i = 0 ; i < tr.viewDef->numDrawSurfs ; i++ ) {
  446. drawSurf = tr.viewDef->drawSurfs[i];
  447. shader = drawSurf->material;
  448. if ( !shader || !shader->HasSubview() ) {
  449. continue;
  450. }
  451. if ( R_GenerateSurfaceSubview( drawSurf ) ) {
  452. subviews = true;
  453. }
  454. }
  455. return subviews;
  456. }