tr_frontend_subview.cpp 16 KB

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