DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

GLMatrix.cpp (16693B)


      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 /*
     35 ==========================================================================================
     36 
     37 OLD MATRIX MATH
     38 
     39 ==========================================================================================
     40 */
     41 
     42 /*
     43 ======================
     44 R_AxisToModelMatrix
     45 ======================
     46 */
     47 void R_AxisToModelMatrix( const idMat3 &axis, const idVec3 &origin, float modelMatrix[16] ) {
     48 	modelMatrix[0 * 4 + 0] = axis[0][0];
     49 	modelMatrix[1 * 4 + 0] = axis[1][0];
     50 	modelMatrix[2 * 4 + 0] = axis[2][0];
     51 	modelMatrix[3 * 4 + 0] = origin[0];
     52 
     53 	modelMatrix[0 * 4 + 1] = axis[0][1];
     54 	modelMatrix[1 * 4 + 1] = axis[1][1];
     55 	modelMatrix[2 * 4 + 1] = axis[2][1];
     56 	modelMatrix[3 * 4 + 1] = origin[1];
     57 
     58 	modelMatrix[0 * 4 + 2] = axis[0][2];
     59 	modelMatrix[1 * 4 + 2] = axis[1][2];
     60 	modelMatrix[2 * 4 + 2] = axis[2][2];
     61 	modelMatrix[3 * 4 + 2] = origin[2];
     62 
     63 	modelMatrix[0 * 4 + 3] = 0.0f;
     64 	modelMatrix[1 * 4 + 3] = 0.0f;
     65 	modelMatrix[2 * 4 + 3] = 0.0f;
     66 	modelMatrix[3 * 4 + 3] = 1.0f;
     67 }
     68 
     69 /*
     70 ==========================
     71 R_MatrixMultiply
     72 ==========================
     73 */
     74 void R_MatrixMultiply( const float a[16], const float b[16], float out[16] ) {
     75 #ifdef ID_WIN_X86_SSE2_INTRIN
     76 
     77 	__m128 a0 = _mm_loadu_ps( a + 0*4 );
     78 	__m128 a1 = _mm_loadu_ps( a + 1*4 );
     79 	__m128 a2 = _mm_loadu_ps( a + 2*4 );
     80 	__m128 a3 = _mm_loadu_ps( a + 3*4 );
     81 
     82 	__m128 b0 = _mm_loadu_ps( b + 0*4 );
     83 	__m128 b1 = _mm_loadu_ps( b + 1*4 );
     84 	__m128 b2 = _mm_loadu_ps( b + 2*4 );
     85 	__m128 b3 = _mm_loadu_ps( b + 3*4 );
     86 
     87 	__m128 t0 = _mm_mul_ps( _mm_splat_ps( a0, 0 ), b0 );
     88 	__m128 t1 = _mm_mul_ps( _mm_splat_ps( a1, 0 ), b0 );
     89 	__m128 t2 = _mm_mul_ps( _mm_splat_ps( a2, 0 ), b0 );
     90 	__m128 t3 = _mm_mul_ps( _mm_splat_ps( a3, 0 ), b0 );
     91 
     92 	t0 = _mm_add_ps( t0, _mm_mul_ps( _mm_splat_ps( a0, 1 ), b1 ) );
     93 	t1 = _mm_add_ps( t1, _mm_mul_ps( _mm_splat_ps( a1, 1 ), b1 ) );
     94 	t2 = _mm_add_ps( t2, _mm_mul_ps( _mm_splat_ps( a2, 1 ), b1 ) );
     95 	t3 = _mm_add_ps( t3, _mm_mul_ps( _mm_splat_ps( a3, 1 ), b1 ) );
     96 
     97 	t0 = _mm_add_ps( t0, _mm_mul_ps( _mm_splat_ps( a0, 2 ), b2 ) );
     98 	t1 = _mm_add_ps( t1, _mm_mul_ps( _mm_splat_ps( a1, 2 ), b2 ) );
     99 	t2 = _mm_add_ps( t2, _mm_mul_ps( _mm_splat_ps( a2, 2 ), b2 ) );
    100 	t3 = _mm_add_ps( t3, _mm_mul_ps( _mm_splat_ps( a3, 2 ), b2 ) );
    101 
    102 	t0 = _mm_add_ps( t0, _mm_mul_ps( _mm_splat_ps( a0, 3 ), b3 ) );
    103 	t1 = _mm_add_ps( t1, _mm_mul_ps( _mm_splat_ps( a1, 3 ), b3 ) );
    104 	t2 = _mm_add_ps( t2, _mm_mul_ps( _mm_splat_ps( a2, 3 ), b3 ) );
    105 	t3 = _mm_add_ps( t3, _mm_mul_ps( _mm_splat_ps( a3, 3 ), b3 ) );
    106 
    107 	_mm_storeu_ps( out + 0*4, t0 );
    108 	_mm_storeu_ps( out + 1*4, t1 );
    109 	_mm_storeu_ps( out + 2*4, t2 );
    110 	_mm_storeu_ps( out + 3*4, t3 );
    111 
    112 #else
    113 
    114 	/*
    115 	for ( int i = 0; i < 4; i++ ) {
    116 		for ( int j = 0; j < 4; j++ ) {
    117 			out[ i * 4 + j ] =
    118 				a[ i * 4 + 0 ] * b[ 0 * 4 + j ] +
    119 				a[ i * 4 + 1 ] * b[ 1 * 4 + j ] +
    120 				a[ i * 4 + 2 ] * b[ 2 * 4 + j ] +
    121 				a[ i * 4 + 3 ] * b[ 3 * 4 + j ];
    122 		}
    123 	}
    124 	*/
    125 
    126 	out[0*4+0] = a[0*4+0]*b[0*4+0] + a[0*4+1]*b[1*4+0] + a[0*4+2]*b[2*4+0] + a[0*4+3]*b[3*4+0];
    127 	out[0*4+1] = a[0*4+0]*b[0*4+1] + a[0*4+1]*b[1*4+1] + a[0*4+2]*b[2*4+1] + a[0*4+3]*b[3*4+1];
    128 	out[0*4+2] = a[0*4+0]*b[0*4+2] + a[0*4+1]*b[1*4+2] + a[0*4+2]*b[2*4+2] + a[0*4+3]*b[3*4+2];
    129 	out[0*4+3] = a[0*4+0]*b[0*4+3] + a[0*4+1]*b[1*4+3] + a[0*4+2]*b[2*4+3] + a[0*4+3]*b[3*4+3];
    130 
    131 	out[1*4+0] = a[1*4+0]*b[0*4+0] + a[1*4+1]*b[1*4+0] + a[1*4+2]*b[2*4+0] + a[1*4+3]*b[3*4+0];
    132 	out[1*4+1] = a[1*4+0]*b[0*4+1] + a[1*4+1]*b[1*4+1] + a[1*4+2]*b[2*4+1] + a[1*4+3]*b[3*4+1];
    133 	out[1*4+2] = a[1*4+0]*b[0*4+2] + a[1*4+1]*b[1*4+2] + a[1*4+2]*b[2*4+2] + a[1*4+3]*b[3*4+2];
    134 	out[1*4+3] = a[1*4+0]*b[0*4+3] + a[1*4+1]*b[1*4+3] + a[1*4+2]*b[2*4+3] + a[1*4+3]*b[3*4+3];
    135 
    136 	out[2*4+0] = a[2*4+0]*b[0*4+0] + a[2*4+1]*b[1*4+0] + a[2*4+2]*b[2*4+0] + a[2*4+3]*b[3*4+0];
    137 	out[2*4+1] = a[2*4+0]*b[0*4+1] + a[2*4+1]*b[1*4+1] + a[2*4+2]*b[2*4+1] + a[2*4+3]*b[3*4+1];
    138 	out[2*4+2] = a[2*4+0]*b[0*4+2] + a[2*4+1]*b[1*4+2] + a[2*4+2]*b[2*4+2] + a[2*4+3]*b[3*4+2];
    139 	out[2*4+3] = a[2*4+0]*b[0*4+3] + a[2*4+1]*b[1*4+3] + a[2*4+2]*b[2*4+3] + a[2*4+3]*b[3*4+3];
    140 
    141 	out[3*4+0] = a[3*4+0]*b[0*4+0] + a[3*4+1]*b[1*4+0] + a[3*4+2]*b[2*4+0] + a[3*4+3]*b[3*4+0];
    142 	out[3*4+1] = a[3*4+0]*b[0*4+1] + a[3*4+1]*b[1*4+1] + a[3*4+2]*b[2*4+1] + a[3*4+3]*b[3*4+1];
    143 	out[3*4+2] = a[3*4+0]*b[0*4+2] + a[3*4+1]*b[1*4+2] + a[3*4+2]*b[2*4+2] + a[3*4+3]*b[3*4+2];
    144 	out[3*4+3] = a[3*4+0]*b[0*4+3] + a[3*4+1]*b[1*4+3] + a[3*4+2]*b[2*4+3] + a[3*4+3]*b[3*4+3];
    145 
    146 #endif
    147 }
    148 
    149 /*
    150 ======================
    151 R_MatrixTranspose
    152 ======================
    153 */
    154 void R_MatrixTranspose( const float in[16], float out[16] ) {
    155 	for ( int i = 0; i < 4; i++ ) {
    156 		for ( int j = 0; j < 4; j++ ) {
    157 			out[i*4+j] = in[j*4+i];
    158 		}
    159 	}
    160 }
    161 
    162 /*
    163 ==========================
    164 R_TransformModelToClip
    165 ==========================
    166 */
    167 void R_TransformModelToClip( const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst ) {
    168 	for ( int i = 0; i < 4; i++ ) {
    169 		eye[i] = 	modelMatrix[i + 0 * 4] * src[0] +
    170 					modelMatrix[i + 1 * 4] * src[1] +
    171 					modelMatrix[i + 2 * 4] * src[2] +
    172 					modelMatrix[i + 3 * 4];
    173 	}
    174 
    175 	for ( int i = 0; i < 4; i++ ) {
    176 		dst[i] = 	projectionMatrix[i + 0 * 4] * eye[0] +
    177 					projectionMatrix[i + 1 * 4] * eye[1] +
    178 					projectionMatrix[i + 2 * 4] * eye[2] +
    179 					projectionMatrix[i + 3 * 4] * eye[3];
    180 	}
    181 }
    182 
    183 /*
    184 ==========================
    185 R_TransformClipToDevice
    186 
    187 Clip to normalized device coordinates
    188 ==========================
    189 */
    190 void R_TransformClipToDevice( const idPlane &clip, idVec3 &ndc ) {
    191 	const float invW = 1.0f / clip[3];
    192 	ndc[0] = clip[0] * invW;
    193 	ndc[1] = clip[1] * invW;
    194 	ndc[2] = clip[2] * invW;		// NOTE: in D3D this is in the range [0,1]
    195 }
    196 
    197 /*
    198 ==========================
    199 R_GlobalToNormalizedDeviceCoordinates
    200 
    201 -1 to 1 range in x, y, and z
    202 ==========================
    203 */
    204 void R_GlobalToNormalizedDeviceCoordinates( const idVec3 &global, idVec3 &ndc ) {
    205 	idPlane	view;
    206 	idPlane	clip;
    207 
    208 	// _D3XP use tr.primaryView when there is no tr.viewDef
    209 	const viewDef_t * viewDef = ( tr.viewDef != NULL ) ? tr.viewDef : tr.primaryView;
    210 
    211 	for ( int i = 0; i < 4; i ++ ) {
    212 		view[i] = 	viewDef->worldSpace.modelViewMatrix[i + 0 * 4] * global[0] +
    213 					viewDef->worldSpace.modelViewMatrix[i + 1 * 4] * global[1] +
    214 					viewDef->worldSpace.modelViewMatrix[i + 2 * 4] * global[2] +
    215 					viewDef->worldSpace.modelViewMatrix[i + 3 * 4];
    216 	}
    217 
    218 	for ( int i = 0; i < 4; i ++ ) {
    219 		clip[i] = 	viewDef->projectionMatrix[i + 0 * 4] * view[0] +
    220 					viewDef->projectionMatrix[i + 1 * 4] * view[1] +
    221 					viewDef->projectionMatrix[i + 2 * 4] * view[2] +
    222 					viewDef->projectionMatrix[i + 3 * 4] * view[3];
    223 	}
    224 
    225 	const float invW = 1.0f / clip[3];
    226 	ndc[0] = clip[0] * invW;
    227 	ndc[1] = clip[1] * invW;
    228 	ndc[2] = clip[2] * invW;		// NOTE: in D3D this is in the range [0,1]
    229 }
    230 
    231 /*
    232 ======================
    233 R_LocalPointToGlobal
    234 
    235 NOTE: assumes no skewing or scaling transforms
    236 ======================
    237 */
    238 void R_LocalPointToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
    239 	out[0] = in[0] * modelMatrix[0 * 4 + 0] + in[1] * modelMatrix[1 * 4 + 0] + in[2] * modelMatrix[2 * 4 + 0] + modelMatrix[3 * 4 + 0];
    240 	out[1] = in[0] * modelMatrix[0 * 4 + 1] + in[1] * modelMatrix[1 * 4 + 1] + in[2] * modelMatrix[2 * 4 + 1] + modelMatrix[3 * 4 + 1];
    241 	out[2] = in[0] * modelMatrix[0 * 4 + 2] + in[1] * modelMatrix[1 * 4 + 2] + in[2] * modelMatrix[2 * 4 + 2] + modelMatrix[3 * 4 + 2];
    242 }
    243 
    244 /*
    245 ======================
    246 R_GlobalPointToLocal
    247 
    248 NOTE: assumes no skewing or scaling transforms
    249 ======================
    250 */
    251 void R_GlobalPointToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
    252 	idVec3 temp;
    253 
    254 	temp[0] = in[0] - modelMatrix[3 * 4 + 0];
    255 	temp[1] = in[1] - modelMatrix[3 * 4 + 1];
    256 	temp[2] = in[2] - modelMatrix[3 * 4 + 2];
    257 
    258 	out[0] = temp[0] * modelMatrix[0 * 4 + 0] + temp[1] * modelMatrix[0 * 4 + 1] + temp[2] * modelMatrix[0 * 4 + 2];
    259 	out[1] = temp[0] * modelMatrix[1 * 4 + 0] + temp[1] * modelMatrix[1 * 4 + 1] + temp[2] * modelMatrix[1 * 4 + 2];
    260 	out[2] = temp[0] * modelMatrix[2 * 4 + 0] + temp[1] * modelMatrix[2 * 4 + 1] + temp[2] * modelMatrix[2 * 4 + 2];
    261 }
    262 
    263 /*
    264 ======================
    265 R_LocalVectorToGlobal
    266 
    267 NOTE: assumes no skewing or scaling transforms
    268 ======================
    269 */
    270 void R_LocalVectorToGlobal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
    271 	out[0] = in[0] * modelMatrix[0 * 4 + 0] + in[1] * modelMatrix[1 * 4 + 0] + in[2] * modelMatrix[2 * 4 + 0];
    272 	out[1] = in[0] * modelMatrix[0 * 4 + 1] + in[1] * modelMatrix[1 * 4 + 1] + in[2] * modelMatrix[2 * 4 + 1];
    273 	out[2] = in[0] * modelMatrix[0 * 4 + 2] + in[1] * modelMatrix[1 * 4 + 2] + in[2] * modelMatrix[2 * 4 + 2];
    274 }
    275 
    276 /*
    277 ======================
    278 R_GlobalVectorToLocal
    279 
    280 NOTE: assumes no skewing or scaling transforms
    281 ======================
    282 */
    283 void R_GlobalVectorToLocal( const float modelMatrix[16], const idVec3 &in, idVec3 &out ) {
    284 	out[0] = in[0] * modelMatrix[0 * 4 + 0] + in[1] * modelMatrix[0 * 4 + 1] + in[2] * modelMatrix[0 * 4 + 2];
    285 	out[1] = in[0] * modelMatrix[1 * 4 + 0] + in[1] * modelMatrix[1 * 4 + 1] + in[2] * modelMatrix[1 * 4 + 2];
    286 	out[2] = in[0] * modelMatrix[2 * 4 + 0] + in[1] * modelMatrix[2 * 4 + 1] + in[2] * modelMatrix[2 * 4 + 2];
    287 }
    288 
    289 /*
    290 ======================
    291 R_GlobalPlaneToLocal
    292 
    293 NOTE: assumes no skewing or scaling transforms
    294 ======================
    295 */
    296 void R_GlobalPlaneToLocal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
    297 	out[0] = in[0] * modelMatrix[0 * 4 + 0] + in[1] * modelMatrix[0 * 4 + 1] + in[2] * modelMatrix[0 * 4 + 2];
    298 	out[1] = in[0] * modelMatrix[1 * 4 + 0] + in[1] * modelMatrix[1 * 4 + 1] + in[2] * modelMatrix[1 * 4 + 2];
    299 	out[2] = in[0] * modelMatrix[2 * 4 + 0] + in[1] * modelMatrix[2 * 4 + 1] + in[2] * modelMatrix[2 * 4 + 2];
    300 	out[3] = in[0] * modelMatrix[3 * 4 + 0] + in[1] * modelMatrix[3 * 4 + 1] + in[2] * modelMatrix[3 * 4 + 2] + in[3];
    301 }
    302 
    303 /*
    304 ======================
    305 R_LocalPlaneToGlobal
    306 
    307 NOTE: assumes no skewing or scaling transforms
    308 ======================
    309 */
    310 void R_LocalPlaneToGlobal( const float modelMatrix[16], const idPlane &in, idPlane &out ) {
    311 	out[0] = in[0] * modelMatrix[0 * 4 + 0] + in[1] * modelMatrix[1 * 4 + 0] + in[2] * modelMatrix[2 * 4 + 0];
    312 	out[1] = in[0] * modelMatrix[0 * 4 + 1] + in[1] * modelMatrix[1 * 4 + 1] + in[2] * modelMatrix[2 * 4 + 1];
    313 	out[2] = in[0] * modelMatrix[0 * 4 + 2] + in[1] * modelMatrix[1 * 4 + 2] + in[2] * modelMatrix[2 * 4 + 2];
    314 	out[3] = in[3] - modelMatrix[3 * 4 + 0] * out[0] - modelMatrix[3 * 4 + 1] * out[1] - modelMatrix[3 * 4 + 2] * out[2];
    315 }
    316 
    317 /*
    318 ==========================================================================================
    319 
    320 WORLD/VIEW/PROJECTION MATRIX SETUP
    321 
    322 ==========================================================================================
    323 */
    324 
    325 /*
    326 ======================
    327 R_SetupViewMatrix
    328 
    329 Sets up the world to view matrix for a given viewParm
    330 ======================
    331 */
    332 void R_SetupViewMatrix( viewDef_t *viewDef ) {
    333 	static float s_flipMatrix[16] = {
    334 		// convert from our coordinate system (looking down X)
    335 		// to OpenGL's coordinate system (looking down -Z)
    336 		 0, 0, -1, 0,
    337 		-1, 0,  0, 0,
    338 		 0, 1,  0, 0,
    339 		 0, 0,  0, 1
    340 	};
    341 
    342 	viewEntity_t *world = &viewDef->worldSpace;
    343 	memset( world, 0, sizeof( *world ) );
    344 
    345 	// the model matrix is an identity
    346 	world->modelMatrix[0*4+0] = 1.0f;
    347 	world->modelMatrix[1*4+1] = 1.0f;
    348 	world->modelMatrix[2*4+2] = 1.0f;
    349 
    350 	// transform by the camera placement
    351 	const idVec3 & origin = viewDef->renderView.vieworg;
    352 	const idMat3 & axis = viewDef->renderView.viewaxis;
    353 
    354 	float viewerMatrix[16];
    355 	viewerMatrix[0*4+0] = axis[0][0];
    356 	viewerMatrix[1*4+0] = axis[0][1];
    357 	viewerMatrix[2*4+0] = axis[0][2];
    358 	viewerMatrix[3*4+0] = - origin[0] * axis[0][0] - origin[1] * axis[0][1] - origin[2] * axis[0][2];
    359 
    360 	viewerMatrix[0*4+1] = axis[1][0];
    361 	viewerMatrix[1*4+1] = axis[1][1];
    362 	viewerMatrix[2*4+1] = axis[1][2];
    363 	viewerMatrix[3*4+1] = - origin[0] * axis[1][0] - origin[1] * axis[1][1] - origin[2] * axis[1][2];
    364 
    365 	viewerMatrix[0*4+2] = axis[2][0];
    366 	viewerMatrix[1*4+2] = axis[2][1];
    367 	viewerMatrix[2*4+2] = axis[2][2];
    368 	viewerMatrix[3*4+2] = - origin[0] * axis[2][0] - origin[1] * axis[2][1] - origin[2] * axis[2][2];
    369 
    370 	viewerMatrix[0*4+3] = 0.0f;
    371 	viewerMatrix[1*4+3] = 0.0f;
    372 	viewerMatrix[2*4+3] = 0.0f;
    373 	viewerMatrix[3*4+3] = 1.0f;
    374 
    375 	// convert from our coordinate system (looking down X)
    376 	// to OpenGL's coordinate system (looking down -Z)
    377 	R_MatrixMultiply( viewerMatrix, s_flipMatrix, world->modelViewMatrix );
    378 }
    379 
    380 /*
    381 ======================
    382 R_SetupProjectionMatrix
    383 
    384 This uses the "infinite far z" trick
    385 ======================
    386 */
    387 idCVar r_centerX( "r_centerX", "0", CVAR_FLOAT, "projection matrix center adjust" );
    388 idCVar r_centerY( "r_centerY", "0", CVAR_FLOAT, "projection matrix center adjust" );
    389 
    390 void R_SetupProjectionMatrix( viewDef_t *viewDef ) {
    391 	// random jittering is usefull when multiple
    392 	// frames are going to be blended together
    393 	// for motion blurred anti-aliasing
    394 	float jitterx, jittery;
    395 	if ( r_jitter.GetBool() ) {
    396 		static idRandom random;
    397 		jitterx = random.RandomFloat();
    398 		jittery = random.RandomFloat();
    399 	} else {
    400 		jitterx = 0.0f;
    401 		jittery = 0.0f;
    402 	}
    403 
    404 	//
    405 	// set up projection matrix
    406 	//
    407 	const float zNear = ( viewDef->renderView.cramZNear ) ? ( r_znear.GetFloat() * 0.25f ) : r_znear.GetFloat();
    408 
    409 	float ymax = zNear * tan( viewDef->renderView.fov_y * idMath::PI / 360.0f );
    410 	float ymin = -ymax;
    411 
    412 	float xmax = zNear * tan( viewDef->renderView.fov_x * idMath::PI / 360.0f );
    413 	float xmin = -xmax;
    414 
    415 	const float width = xmax - xmin;
    416 	const float height = ymax - ymin;
    417 
    418 	const int viewWidth = viewDef->viewport.x2 - viewDef->viewport.x1 + 1;
    419 	const int viewHeight = viewDef->viewport.y2 - viewDef->viewport.y1 + 1;
    420 
    421 	jitterx = jitterx * width / viewWidth;
    422 	jitterx += r_centerX.GetFloat();
    423 	jitterx += viewDef->renderView.stereoScreenSeparation;
    424 	xmin += jitterx * width;
    425 	xmax += jitterx * width;
    426 
    427 	jittery = jittery * height / viewHeight;
    428 	jittery += r_centerY.GetFloat();
    429 	ymin += jittery * height;
    430 	ymax += jittery * height;
    431 
    432 	viewDef->projectionMatrix[0*4+0] = 2.0f * zNear / width;
    433 	viewDef->projectionMatrix[1*4+0] = 0.0f;
    434 	viewDef->projectionMatrix[2*4+0] = ( xmax + xmin ) / width;	// normally 0
    435 	viewDef->projectionMatrix[3*4+0] = 0.0f;
    436 
    437 	viewDef->projectionMatrix[0*4+1] = 0.0f;
    438 	viewDef->projectionMatrix[1*4+1] = 2.0f * zNear / height;
    439 	viewDef->projectionMatrix[2*4+1] = ( ymax + ymin ) / height;	// normally 0
    440 	viewDef->projectionMatrix[3*4+1] = 0.0f;
    441 
    442 	// this is the far-plane-at-infinity formulation, and
    443 	// crunches the Z range slightly so w=0 vertexes do not
    444 	// rasterize right at the wraparound point
    445 	viewDef->projectionMatrix[0*4+2] = 0.0f;
    446 	viewDef->projectionMatrix[1*4+2] = 0.0f;
    447 	viewDef->projectionMatrix[2*4+2] = -0.999f; // adjust value to prevent imprecision issues
    448 	viewDef->projectionMatrix[3*4+2] = -2.0f * zNear;
    449 
    450 	viewDef->projectionMatrix[0*4+3] = 0.0f;
    451 	viewDef->projectionMatrix[1*4+3] = 0.0f;
    452 	viewDef->projectionMatrix[2*4+3] = -1.0f;
    453 	viewDef->projectionMatrix[3*4+3] = 0.0f;
    454 
    455 	if ( viewDef->renderView.flipProjection ) {
    456 		viewDef->projectionMatrix[1*4+1] = -viewDef->projectionMatrix[1*4+1];
    457 		viewDef->projectionMatrix[1*4+3] = -viewDef->projectionMatrix[1*4+3];
    458 	}
    459 }