DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

GuiModel.cpp (12351B)


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