📄 tr_main.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_main.c -- main control flow for each frame
#include "tr_local.h"
trGlobals_t tr;
static float s_flipMatrix[16] = {
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0, 0, -1, 0,
-1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 0, 1
};
refimport_t ri;
// entities that will have procedurally generated surfaces will just
// point at this for their sorting surface
surfaceType_t entitySurface = SF_ENTITY;
/*
=================
R_CullLocalBox
Returns CULL_IN, CULL_CLIP, or CULL_OUT
=================
*/
int R_CullLocalBox (vec3_t bounds[2]) {
int i, j;
vec3_t transformed[8];
float dists[8];
vec3_t v;
cplane_t *frust;
int anyBack;
int front, back;
if ( r_nocull->integer ) {
return CULL_CLIP;
}
// transform into world space
for (i = 0 ; i < 8 ; i++) {
v[0] = bounds[i&1][0];
v[1] = bounds[(i>>1)&1][1];
v[2] = bounds[(i>>2)&1][2];
VectorCopy( tr.or.origin, transformed[i] );
VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
}
// check against frustum planes
anyBack = 0;
for (i = 0 ; i < 4 ; i++) {
frust = &tr.viewParms.frustum[i];
front = back = 0;
for (j = 0 ; j < 8 ; j++) {
dists[j] = DotProduct(transformed[j], frust->normal);
if ( dists[j] > frust->dist ) {
front = 1;
if ( back ) {
break; // a point is in front
}
} else {
back = 1;
}
}
if ( !front ) {
// all points were behind one of the planes
return CULL_OUT;
}
anyBack |= back;
}
if ( !anyBack ) {
return CULL_IN; // completely inside frustum
}
return CULL_CLIP; // partially clipped
}
/*
** R_CullLocalPointAndRadius
*/
int R_CullLocalPointAndRadius( vec3_t pt, float radius )
{
vec3_t transformed;
R_LocalPointToWorld( pt, transformed );
return R_CullPointAndRadius( transformed, radius );
}
/*
** R_CullPointAndRadius
*/
int R_CullPointAndRadius( vec3_t pt, float radius )
{
int i;
float dist;
cplane_t *frust;
qboolean mightBeClipped = qfalse;
if ( r_nocull->integer ) {
return CULL_CLIP;
}
// check against frustum planes
for (i = 0 ; i < 4 ; i++)
{
frust = &tr.viewParms.frustum[i];
dist = DotProduct( pt, frust->normal) - frust->dist;
if ( dist < -radius )
{
return CULL_OUT;
}
else if ( dist <= radius )
{
mightBeClipped = qtrue;
}
}
if ( mightBeClipped )
{
return CULL_CLIP;
}
return CULL_IN; // completely inside frustum
}
/*
=================
R_LocalNormalToWorld
=================
*/
void R_LocalNormalToWorld (vec3_t local, vec3_t world) {
world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];
world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];
world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];
}
/*
=================
R_LocalPointToWorld
=================
*/
void R_LocalPointToWorld (vec3_t local, vec3_t world) {
world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0] + tr.or.origin[0];
world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1] + tr.or.origin[1];
world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2] + tr.or.origin[2];
}
/*
=================
R_WorldToLocal
=================
*/
void R_WorldToLocal (vec3_t world, vec3_t local) {
local[0] = DotProduct(world, tr.or.axis[0]);
local[1] = DotProduct(world, tr.or.axis[1]);
local[2] = DotProduct(world, tr.or.axis[2]);
}
/*
==========================
R_TransformModelToClip
==========================
*/
void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
vec4_t eye, vec4_t dst ) {
int i;
for ( i = 0 ; i < 4 ; i++ ) {
eye[i] =
src[0] * modelMatrix[ i + 0 * 4 ] +
src[1] * modelMatrix[ i + 1 * 4 ] +
src[2] * modelMatrix[ i + 2 * 4 ] +
1 * modelMatrix[ i + 3 * 4 ];
}
for ( i = 0 ; i < 4 ; i++ ) {
dst[i] =
eye[0] * projectionMatrix[ i + 0 * 4 ] +
eye[1] * projectionMatrix[ i + 1 * 4 ] +
eye[2] * projectionMatrix[ i + 2 * 4 ] +
eye[3] * projectionMatrix[ i + 3 * 4 ];
}
}
/*
==========================
R_TransformClipToWindow
==========================
*/
void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
normalized[0] = clip[0] / clip[3];
normalized[1] = clip[1] / clip[3];
normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
window[2] = normalized[2];
window[0] = (int) ( window[0] + 0.5 );
window[1] = (int) ( window[1] + 0.5 );
}
/*
==========================
myGlMultMatrix
==========================
*/
void myGlMultMatrix( const float *a, const float *b, float *out ) {
int i, j;
for ( i = 0 ; i < 4 ; i++ ) {
for ( j = 0 ; j < 4 ; j++ ) {
out[ i * 4 + j ] =
a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
}
}
}
/*
=================
R_RotateForEntity
Generates an orientation for an entity and viewParms
Does NOT produce any GL calls
Called by both the front end and the back end
=================
*/
void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
orientationr_t *or ) {
float glMatrix[16];
vec3_t delta;
float axisLength;
if ( ent->e.reType != RT_MODEL ) {
*or = viewParms->world;
return;
}
VectorCopy( ent->e.origin, or->origin );
VectorCopy( ent->e.axis[0], or->axis[0] );
VectorCopy( ent->e.axis[1], or->axis[1] );
VectorCopy( ent->e.axis[2], or->axis[2] );
glMatrix[0] = or->axis[0][0];
glMatrix[4] = or->axis[1][0];
glMatrix[8] = or->axis[2][0];
glMatrix[12] = or->origin[0];
glMatrix[1] = or->axis[0][1];
glMatrix[5] = or->axis[1][1];
glMatrix[9] = or->axis[2][1];
glMatrix[13] = or->origin[1];
glMatrix[2] = or->axis[0][2];
glMatrix[6] = or->axis[1][2];
glMatrix[10] = or->axis[2][2];
glMatrix[14] = or->origin[2];
glMatrix[3] = 0;
glMatrix[7] = 0;
glMatrix[11] = 0;
glMatrix[15] = 1;
myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
// calculate the viewer origin in the model's space
// needed for fog, specular, and environment mapping
VectorSubtract( viewParms->or.origin, or->origin, delta );
// compensate for scale in the axes if necessary
if ( ent->e.nonNormalizedAxes ) {
axisLength = VectorLength( ent->e.axis[0] );
if ( !axisLength ) {
axisLength = 0;
} else {
axisLength = 1.0f / axisLength;
}
} else {
axisLength = 1.0f;
}
or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;
or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;
or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
}
/*
=================
R_RotateForViewer
Sets up the modelview matrix for a given viewParm
=================
*/
void R_RotateForViewer (void)
{
float viewerMatrix[16];
vec3_t origin;
Com_Memset (&tr.or, 0, sizeof(tr.or));
tr.or.axis[0][0] = 1;
tr.or.axis[1][1] = 1;
tr.or.axis[2][2] = 1;
VectorCopy (tr.viewParms.or.origin, tr.or.viewOrigin);
// transform by the camera placement
VectorCopy( tr.viewParms.or.origin, origin );
viewerMatrix[0] = tr.viewParms.or.axis[0][0];
viewerMatrix[4] = tr.viewParms.or.axis[0][1];
viewerMatrix[8] = tr.viewParms.or.axis[0][2];
viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
viewerMatrix[1] = tr.viewParms.or.axis[1][0];
viewerMatrix[5] = tr.viewParms.or.axis[1][1];
viewerMatrix[9] = tr.viewParms.or.axis[1][2];
viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
viewerMatrix[2] = tr.viewParms.or.axis[2][0];
viewerMatrix[6] = tr.viewParms.or.axis[2][1];
viewerMatrix[10] = tr.viewParms.or.axis[2][2];
viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
viewerMatrix[3] = 0;
viewerMatrix[7] = 0;
viewerMatrix[11] = 0;
viewerMatrix[15] = 1;
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );
tr.viewParms.world = tr.or;
}
/*
** SetFarClip
*/
static void SetFarClip( void )
{
float farthestCornerDistance = 0;
int i;
// if not rendering the world (icons, menus, etc)
// set a 2k far clip plane
if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
tr.viewParms.zFar = 2048;
return;
}
//
// set far clipping planes dynamically
//
farthestCornerDistance = 0;
for ( i = 0; i < 8; i++ )
{
vec3_t v;
vec3_t vecTo;
float distance;
if ( i & 1 )
{
v[0] = tr.viewParms.visBounds[0][0];
}
else
{
v[0] = tr.viewParms.visBounds[1][0];
}
if ( i & 2 )
{
v[1] = tr.viewParms.visBounds[0][1];
}
else
{
v[1] = tr.viewParms.visBounds[1][1];
}
if ( i & 4 )
{
v[2] = tr.viewParms.visBounds[0][2];
}
else
{
v[2] = tr.viewParms.visBounds[1][2];
}
VectorSubtract( v, tr.viewParms.or.origin, vecTo );
distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
if ( distance > farthestCornerDistance )
{
farthestCornerDistance = distance;
}
}
tr.viewParms.zFar = sqrt( farthestCornerDistance );
}
/*
===============
R_SetupProjection
===============
*/
void R_SetupProjection( void ) {
float xmin, xmax, ymin, ymax;
float width, height, depth;
float zNear, zFar;
// dynamically compute far clip plane distance
SetFarClip();
//
// set up projection matrix
//
zNear = r_znear->value;
zFar = tr.viewParms.zFar;
ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
ymin = -ymax;
xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
xmin = -xmax;
width = xmax - xmin;
height = ymax - ymin;
depth = zFar - zNear;
tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
tr.viewParms.projectionMatrix[4] = 0;
tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
tr.viewParms.projectionMatrix[12] = 0;
tr.viewParms.projectionMatrix[1] = 0;
tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
tr.viewParms.projectionMatrix[13] = 0;
tr.viewParms.projectionMatrix[2] = 0;
tr.viewParms.projectionMatrix[6] = 0;
tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
tr.viewParms.projectionMatrix[3] = 0;
tr.viewParms.projectionMatrix[7] = 0;
tr.viewParms.projectionMatrix[11] = -1;
tr.viewParms.projectionMatrix[15] = 0;
}
/*
=================
R_SetupFrustum
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -