GuiModel.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  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. const float idGuiModel::STEREO_DEPTH_NEAR = 0.0f;
  24. const float idGuiModel::STEREO_DEPTH_MID = 0.5f;
  25. const float idGuiModel::STEREO_DEPTH_FAR = 1.0f;
  26. /*
  27. ================
  28. idGuiModel::idGuiModel
  29. ================
  30. */
  31. idGuiModel::idGuiModel() {
  32. // identity color for drawsurf register evaluation
  33. for ( int i = 0; i < MAX_ENTITY_SHADER_PARMS; i++ ) {
  34. shaderParms[i] = 1.0f;
  35. }
  36. }
  37. /*
  38. ================
  39. idGuiModel::Clear
  40. Begins collecting draw commands into surfaces
  41. ================
  42. */
  43. void idGuiModel::Clear() {
  44. surfaces.SetNum( 0 );
  45. AdvanceSurf();
  46. }
  47. /*
  48. ================
  49. idGuiModel::WriteToDemo
  50. ================
  51. */
  52. void idGuiModel::WriteToDemo( idDemoFile *demo ) {
  53. }
  54. /*
  55. ================
  56. idGuiModel::ReadFromDemo
  57. ================
  58. */
  59. void idGuiModel::ReadFromDemo( idDemoFile *demo ) {
  60. }
  61. /*
  62. ================
  63. idGuiModel::BeginFrame
  64. ================
  65. */
  66. void idGuiModel::BeginFrame() {
  67. vertexBlock = vertexCache.AllocVertex( NULL, ALIGN( MAX_VERTS * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
  68. indexBlock = vertexCache.AllocIndex( NULL, ALIGN( MAX_INDEXES * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
  69. vertexPointer = (idDrawVert *)vertexCache.MappedVertexBuffer( vertexBlock );
  70. indexPointer = (triIndex_t *)vertexCache.MappedIndexBuffer( indexBlock );
  71. numVerts = 0;
  72. numIndexes = 0;
  73. Clear();
  74. }
  75. idCVar stereoRender_defaultGuiDepth( "stereoRender_defaultGuiDepth", "0", CVAR_RENDERER, "Fraction of separation when not specified" );
  76. /*
  77. ================
  78. EmitSurfaces
  79. For full screen GUIs, we can add in per-surface stereoscopic depth effects
  80. ================
  81. */
  82. void idGuiModel::EmitSurfaces( float modelMatrix[16], float modelViewMatrix[16],
  83. bool depthHack, bool allowFullScreenStereoDepth, bool linkAsEntity ) {
  84. viewEntity_t * guiSpace = (viewEntity_t *)R_ClearedFrameAlloc( sizeof( *guiSpace ), FRAME_ALLOC_VIEW_ENTITY );
  85. memcpy( guiSpace->modelMatrix, modelMatrix, sizeof( guiSpace->modelMatrix ) );
  86. memcpy( guiSpace->modelViewMatrix, modelViewMatrix, sizeof( guiSpace->modelViewMatrix ) );
  87. guiSpace->weaponDepthHack = depthHack;
  88. guiSpace->isGuiSurface = true;
  89. // If this is an in-game gui, we need to be able to find the matrix again for head mounted
  90. // display bypass matrix fixup.
  91. if ( linkAsEntity ) {
  92. guiSpace->next = tr.viewDef->viewEntitys;
  93. tr.viewDef->viewEntitys = guiSpace;
  94. }
  95. //---------------------------
  96. // make a tech5 renderMatrix
  97. //---------------------------
  98. idRenderMatrix viewMat;
  99. idRenderMatrix::Transpose( *(idRenderMatrix *)modelViewMatrix, viewMat );
  100. idRenderMatrix::Multiply( tr.viewDef->projectionRenderMatrix, viewMat, guiSpace->mvp );
  101. if ( depthHack ) {
  102. idRenderMatrix::ApplyDepthHack( guiSpace->mvp );
  103. }
  104. // to allow 3D-TV effects in the menu system, we define surface flags to set
  105. // depth fractions between 0=screen and 1=infinity, which directly modulate the
  106. // screenSeparation parameter for an X offset.
  107. // The value is stored in the drawSurf sort value, which adjusts the matrix in the
  108. // backend.
  109. float defaultStereoDepth = stereoRender_defaultGuiDepth.GetFloat(); // default to at-screen
  110. // add the surfaces to this view
  111. for ( int i = 0; i < surfaces.Num(); i++ ) {
  112. const guiModelSurface_t & guiSurf = surfaces[i];
  113. if ( guiSurf.numIndexes == 0 ) {
  114. continue;
  115. }
  116. const idMaterial * shader = guiSurf.material;
  117. drawSurf_t * drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ), FRAME_ALLOC_DRAW_SURFACE );
  118. drawSurf->numIndexes = guiSurf.numIndexes;
  119. drawSurf->ambientCache = vertexBlock;
  120. // build a vertCacheHandle_t that points inside the allocated block
  121. drawSurf->indexCache = indexBlock + ( (int64)(guiSurf.firstIndex*sizeof(triIndex_t)) << VERTCACHE_OFFSET_SHIFT );
  122. drawSurf->shadowCache = 0;
  123. drawSurf->jointCache = 0;
  124. drawSurf->frontEndGeo = NULL;
  125. drawSurf->space = guiSpace;
  126. drawSurf->material = shader;
  127. drawSurf->extraGLState = guiSurf.glState;
  128. drawSurf->scissorRect = tr.viewDef->scissor;
  129. drawSurf->sort = shader->GetSort();
  130. drawSurf->renderZFail = 0;
  131. // process the shader expressions for conditionals / color / texcoords
  132. const float *constRegs = shader->ConstantRegisters();
  133. if ( constRegs ) {
  134. // shader only uses constant values
  135. drawSurf->shaderRegisters = constRegs;
  136. } else {
  137. float *regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ), FRAME_ALLOC_SHADER_REGISTER );
  138. drawSurf->shaderRegisters = regs;
  139. shader->EvaluateRegisters( regs, shaderParms, tr.viewDef->renderView.shaderParms, tr.viewDef->renderView.time[1] * 0.001f, NULL );
  140. }
  141. R_LinkDrawSurfToView( drawSurf, tr.viewDef );
  142. if ( allowFullScreenStereoDepth ) {
  143. // override sort with the stereoDepth
  144. //drawSurf->sort = stereoDepth;
  145. switch ( guiSurf.stereoType ) {
  146. case STEREO_DEPTH_TYPE_NEAR: drawSurf->sort = STEREO_DEPTH_NEAR; break;
  147. case STEREO_DEPTH_TYPE_MID: drawSurf->sort = STEREO_DEPTH_MID; break;
  148. case STEREO_DEPTH_TYPE_FAR: drawSurf->sort = STEREO_DEPTH_FAR; break;
  149. case STEREO_DEPTH_TYPE_NONE:
  150. default:
  151. drawSurf->sort = defaultStereoDepth;
  152. break;
  153. }
  154. }
  155. }
  156. }
  157. /*
  158. ====================
  159. EmitToCurrentView
  160. ====================
  161. */
  162. void idGuiModel::EmitToCurrentView( float modelMatrix[16], bool depthHack ) {
  163. float modelViewMatrix[16];
  164. R_MatrixMultiply( modelMatrix, tr.viewDef->worldSpace.modelViewMatrix, modelViewMatrix );
  165. EmitSurfaces( modelMatrix, modelViewMatrix, depthHack, false /* stereoDepthSort */, true /* link as entity */ );
  166. }
  167. /*
  168. ================
  169. idGuiModel::EmitFullScreen
  170. Creates a view that covers the screen and emit the surfaces
  171. ================
  172. */
  173. void idGuiModel::EmitFullScreen() {
  174. if ( surfaces[0].numIndexes == 0 ) {
  175. return;
  176. }
  177. SCOPED_PROFILE_EVENT( "Gui::EmitFullScreen" );
  178. viewDef_t * viewDef = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *viewDef ), FRAME_ALLOC_VIEW_DEF );
  179. viewDef->is2Dgui = true;
  180. tr.GetCroppedViewport( &viewDef->viewport );
  181. bool stereoEnabled = ( renderSystem->GetStereo3DMode() != STEREO3D_OFF );
  182. if ( stereoEnabled ) {
  183. float GetScreenSeparationForGuis();
  184. const float screenSeparation = GetScreenSeparationForGuis();
  185. // this will be negated on the alternate eyes, both rendered each frame
  186. viewDef->renderView.stereoScreenSeparation = screenSeparation;
  187. extern idCVar stereoRender_swapEyes;
  188. viewDef->renderView.viewEyeBuffer = 0; // render to both buffers
  189. if ( stereoRender_swapEyes.GetBool() ) {
  190. viewDef->renderView.stereoScreenSeparation = -screenSeparation;
  191. }
  192. }
  193. viewDef->scissor.x1 = 0;
  194. viewDef->scissor.y1 = 0;
  195. viewDef->scissor.x2 = viewDef->viewport.x2 - viewDef->viewport.x1;
  196. viewDef->scissor.y2 = viewDef->viewport.y2 - viewDef->viewport.y1;
  197. viewDef->projectionMatrix[0*4+0] = 2.0f / SCREEN_WIDTH;
  198. viewDef->projectionMatrix[0*4+1] = 0.0f;
  199. viewDef->projectionMatrix[0*4+2] = 0.0f;
  200. viewDef->projectionMatrix[0*4+3] = 0.0f;
  201. viewDef->projectionMatrix[1*4+0] = 0.0f;
  202. viewDef->projectionMatrix[1*4+1] = -2.0f / SCREEN_HEIGHT;
  203. viewDef->projectionMatrix[1*4+2] = 0.0f;
  204. viewDef->projectionMatrix[1*4+3] = 0.0f;
  205. viewDef->projectionMatrix[2*4+0] = 0.0f;
  206. viewDef->projectionMatrix[2*4+1] = 0.0f;
  207. viewDef->projectionMatrix[2*4+2] = -2.0f;
  208. viewDef->projectionMatrix[2*4+3] = 0.0f;
  209. viewDef->projectionMatrix[3*4+0] = -1.0f;
  210. viewDef->projectionMatrix[3*4+1] = 1.0f;
  211. viewDef->projectionMatrix[3*4+2] = -1.0f;
  212. viewDef->projectionMatrix[3*4+3] = 1.0f;
  213. // make a tech5 renderMatrix for faster culling
  214. idRenderMatrix::Transpose( *(idRenderMatrix *)viewDef->projectionMatrix, viewDef->projectionRenderMatrix );
  215. viewDef->worldSpace.modelMatrix[0*4+0] = 1.0f;
  216. viewDef->worldSpace.modelMatrix[1*4+1] = 1.0f;
  217. viewDef->worldSpace.modelMatrix[2*4+2] = 1.0f;
  218. viewDef->worldSpace.modelMatrix[3*4+3] = 1.0f;
  219. viewDef->worldSpace.modelViewMatrix[0*4+0] = 1.0f;
  220. viewDef->worldSpace.modelViewMatrix[1*4+1] = 1.0f;
  221. viewDef->worldSpace.modelViewMatrix[2*4+2] = 1.0f;
  222. viewDef->worldSpace.modelViewMatrix[3*4+3] = 1.0f;
  223. viewDef->maxDrawSurfs = surfaces.Num();
  224. viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ), FRAME_ALLOC_DRAW_SURFACE_POINTER );
  225. viewDef->numDrawSurfs = 0;
  226. viewDef_t * oldViewDef = tr.viewDef;
  227. tr.viewDef = viewDef;
  228. EmitSurfaces( viewDef->worldSpace.modelMatrix, viewDef->worldSpace.modelViewMatrix,
  229. false /* depthHack */ , stereoEnabled /* stereoDepthSort */, false /* link as entity */ );
  230. tr.viewDef = oldViewDef;
  231. // add the command to draw this view
  232. R_AddDrawViewCmd( viewDef, true );
  233. }
  234. /*
  235. =============
  236. AdvanceSurf
  237. =============
  238. */
  239. void idGuiModel::AdvanceSurf() {
  240. guiModelSurface_t s;
  241. if ( surfaces.Num() ) {
  242. s.material = surf->material;
  243. s.glState = surf->glState;
  244. } else {
  245. s.material = tr.defaultMaterial;
  246. s.glState = 0;
  247. }
  248. // advance indexes so the pointer to each surface will be 16 byte aligned
  249. numIndexes = ALIGN( numIndexes, 8 );
  250. s.numIndexes = 0;
  251. s.firstIndex = numIndexes;
  252. surfaces.Append( s );
  253. surf = &surfaces[ surfaces.Num() - 1 ];
  254. }
  255. /*
  256. =============
  257. AllocTris
  258. =============
  259. */
  260. idDrawVert * idGuiModel::AllocTris( int vertCount, const triIndex_t * tempIndexes, int indexCount, const idMaterial * material, const uint64 glState, const stereoDepthType_t stereoType ) {
  261. if ( material == NULL ) {
  262. return NULL;
  263. }
  264. if ( numIndexes + indexCount > MAX_INDEXES ) {
  265. static int warningFrame = 0;
  266. if ( warningFrame != tr.frameCount ) {
  267. warningFrame = tr.frameCount;
  268. idLib::Warning( "idGuiModel::AllocTris: MAX_INDEXES exceeded" );
  269. }
  270. return NULL;
  271. }
  272. if ( numVerts + vertCount > MAX_VERTS ) {
  273. static int warningFrame = 0;
  274. if ( warningFrame != tr.frameCount ) {
  275. warningFrame = tr.frameCount;
  276. idLib::Warning( "idGuiModel::AllocTris: MAX_VERTS exceeded" );
  277. }
  278. return NULL;
  279. }
  280. // break the current surface if we are changing to a new material or we can't
  281. // fit the data into our allocated block
  282. if ( material != surf->material || glState != surf->glState || stereoType != surf->stereoType ) {
  283. if ( surf->numIndexes ) {
  284. AdvanceSurf();
  285. }
  286. surf->material = material;
  287. surf->glState = glState;
  288. surf->stereoType = stereoType;
  289. }
  290. int startVert = numVerts;
  291. int startIndex = numIndexes;
  292. numVerts += vertCount;
  293. numIndexes += indexCount;
  294. surf->numIndexes += indexCount;
  295. if ( ( startIndex & 1 ) || ( indexCount & 1 ) ) {
  296. // slow for write combined memory!
  297. // this should be very rare, since quads are always an even index count
  298. for ( int i = 0; i < indexCount; i++ ) {
  299. indexPointer[startIndex + i] = startVert + tempIndexes[i];
  300. }
  301. } else {
  302. for ( int i = 0; i < indexCount; i += 2 ) {
  303. WriteIndexPair( indexPointer + startIndex + i, startVert + tempIndexes[i], startVert + tempIndexes[i+1] );
  304. }
  305. }
  306. return vertexPointer + startVert;
  307. }