diff options
Diffstat (limited to 'src/rend2/tr_main.c')
-rw-r--r-- | src/rend2/tr_main.c | 2882 |
1 files changed, 0 insertions, 2882 deletions
diff --git a/src/rend2/tr_main.c b/src/rend2/tr_main.c deleted file mode 100644 index 0935dce7..00000000 --- a/src/rend2/tr_main.c +++ /dev/null @@ -1,2882 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; 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" - -#include <string.h> // memcpy - -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_CompareVert -================ -*/ -qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST) -{ - int i; - - for(i = 0; i < 3; i++) - { - if(floor(v1->xyz[i] + 0.1) != floor(v2->xyz[i] + 0.1)) - { - return qfalse; - } - - if(checkST && ((v1->st[0] != v2->st[0]) || (v1->st[1] != v2->st[1]))) - { - return qfalse; - } - } - - return qtrue; -} - -/* -============= -R_CalcNormalForTriangle -============= -*/ -void R_CalcNormalForTriangle(vec3_t normal, const vec3_t v0, const vec3_t v1, const vec3_t v2) -{ - vec3_t udir, vdir; - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, udir); - VectorSubtract(v1, v0, vdir); - CrossProduct(udir, vdir, normal); - - VectorNormalize(normal); -} - -/* -============= -R_CalcTangentsForTriangle -http://members.rogers.com/deseric/tangentspace.htm -============= -*/ -void R_CalcTangentsForTriangle(vec3_t tangent, vec3_t bitangent, - const vec3_t v0, const vec3_t v1, const vec3_t v2, - const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - int i; - vec3_t planes[3]; - vec3_t u, v; - - for(i = 0; i < 3; i++) - { - VectorSet(u, v1[i] - v0[i], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[i] - v0[i], t2[0] - t0[0], t2[1] - t0[1]); - - VectorNormalize(u); - VectorNormalize(v); - - CrossProduct(u, v, planes[i]); - } - - //So your tangent space will be defined by this : - //Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product, - // you have to make sure the normal points in the right direction) - //Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az ) - //Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az ) - - // tangent... - tangent[0] = -planes[0][1] / planes[0][0]; - tangent[1] = -planes[1][1] / planes[1][0]; - tangent[2] = -planes[2][1] / planes[2][0]; - VectorNormalize(tangent); - - // bitangent... - bitangent[0] = -planes[0][2] / planes[0][0]; - bitangent[1] = -planes[1][2] / planes[1][0]; - bitangent[2] = -planes[2][2] / planes[2][0]; - VectorNormalize(bitangent); -} - - - - -/* -============= -R_CalcTangentSpace -============= -*/ -void R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalize(tangent); - VectorNormalize(bitangent); - - // compute the face normal based on vertex points - if ( normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f ) - { - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - } - else - { - VectorCopy(normal, faceNormal); - } - - VectorNormalize(faceNormal); - -#if 1 - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalize(tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); -#else - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalize(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - //VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - // compute the cross product T=BxN - CrossProduct(bitangent, faceNormal, tangent); - - // compute the cross product B=NxT - //CrossProduct(normal, tangent, bitangent); - } -#endif - - VectorCopy(faceNormal, normal); -} - -void R_CalcTangentSpaceFast(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v0, const vec3_t v1, const vec3_t v2, const vec2_t t0, const vec2_t t1, const vec2_t t2) -{ - vec3_t cp, u, v; - vec3_t faceNormal; - - VectorSet(u, v1[0] - v0[0], t1[0] - t0[0], t1[1] - t0[1]); - VectorSet(v, v2[0] - v0[0], t2[0] - t0[0], t2[1] - t0[1]); - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[0] = -cp[1] / cp[0]; - bitangent[0] = -cp[2] / cp[0]; - } - - u[0] = v1[1] - v0[1]; - v[0] = v2[1] - v0[1]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[1] = -cp[1] / cp[0]; - bitangent[1] = -cp[2] / cp[0]; - } - - u[0] = v1[2] - v0[2]; - v[0] = v2[2] - v0[2]; - - CrossProduct(u, v, cp); - if(fabs(cp[0]) > 10e-6) - { - tangent[2] = -cp[1] / cp[0]; - bitangent[2] = -cp[2] / cp[0]; - } - - VectorNormalizeFast(tangent); - VectorNormalizeFast(bitangent); - - // compute the face normal based on vertex points - VectorSubtract(v2, v0, u); - VectorSubtract(v1, v0, v); - CrossProduct(u, v, faceNormal); - - VectorNormalizeFast(faceNormal); - -#if 0 - // normal, compute the cross product N=TxB - CrossProduct(tangent, bitangent, normal); - VectorNormalizeFast(normal); - - if(DotProduct(normal, faceNormal) < 0) - { - VectorInverse(normal); - //VectorInverse(tangent); - //VectorInverse(bitangent); - - CrossProduct(normal, tangent, bitangent); - } - - VectorCopy(faceNormal, normal); -#else - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - VectorMA(tangent, -DotProduct(faceNormal, tangent), faceNormal, tangent); - VectorNormalizeFast(tangent); -#endif - - VectorCopy(faceNormal, normal); -} - -/* -http://www.terathon.com/code/tangent.html -*/ -void R_CalcTBN(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3) -{ - vec3_t u, v; - float x1, x2, y1, y2, z1, z2; - float s1, s2, t1, t2; - float r, dot; - - x1 = v2[0] - v1[0]; - x2 = v3[0] - v1[0]; - y1 = v2[1] - v1[1]; - y2 = v3[1] - v1[1]; - z1 = v2[2] - v1[2]; - z2 = v3[2] - v1[2]; - - s1 = w2[0] - w1[0]; - s2 = w3[0] - w1[0]; - t1 = w2[1] - w1[1]; - t2 = w3[1] - w1[1]; - - r = 1.0f / (s1 * t2 - s2 * t1); - - VectorSet(tangent, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r); - VectorSet(bitangent, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r); - - // compute the face normal based on vertex points - VectorSubtract(v3, v1, u); - VectorSubtract(v2, v1, v); - CrossProduct(u, v, normal); - - VectorNormalize(normal); - - // Gram-Schmidt orthogonalize - //tangent[a] = (t - n * Dot(n, t)).Normalize(); - dot = DotProduct(normal, tangent); - VectorMA(tangent, -dot, normal, tangent); - VectorNormalize(tangent); - - // B=NxT - //CrossProduct(normal, tangent, bitangent); -} - -void R_CalcTBN2(vec3_t tangent, vec3_t bitangent, vec3_t normal, - const vec3_t v1, const vec3_t v2, const vec3_t v3, const vec2_t t1, const vec2_t t2, const vec2_t t3) -{ - vec3_t v2v1; - vec3_t v3v1; - - float c2c1_T; - float c2c1_B; - - float c3c1_T; - float c3c1_B; - - float denominator; - float scale1, scale2; - - vec3_t T, B, N, C; - - - // Calculate the tangent basis for each vertex of the triangle - // UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has - // been removed as it was redundant (the entire TBN matrix was calculated three times - // instead of just one). - // - // Please note, that this function relies on the fact that the input geometry are triangles - // and the tangent basis for each vertex thus is identical! - // - - // Calculate the vectors from the current vertex to the two other vertices in the triangle - VectorSubtract(v2, v1, v2v1); - VectorSubtract(v3, v1, v3v1); - - // The equation presented in the article states that: - // c2c1_T = V2.texcoord.x - V1.texcoord.x - // c2c1_B = V2.texcoord.y - V1.texcoord.y - // c3c1_T = V3.texcoord.x - V1.texcoord.x - // c3c1_B = V3.texcoord.y - V1.texcoord.y - - // Calculate c2c1_T and c2c1_B - c2c1_T = t2[0] - t1[0]; - c2c1_B = t2[1] - t2[1]; - - // Calculate c3c1_T and c3c1_B - c3c1_T = t3[0] - t1[0]; - c3c1_B = t3[1] - t1[1]; - - denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B; - //if(ROUNDOFF(fDenominator) == 0.0f) - if(denominator == 0.0f) - { - // We won't risk a divide by zero, so set the tangent matrix to the identity matrix - VectorSet(tangent, 1, 0, 0); - VectorSet(bitangent, 0, 1, 0); - VectorSet(normal, 0, 0, 1); - } - else - { - // Calculate the reciprocal value once and for all (to achieve speed) - scale1 = 1.0f / denominator; - - // T and B are calculated just as the equation in the article states - VectorSet(T, (c3c1_B * v2v1[0] - c2c1_B * v3v1[0]) * scale1, - (c3c1_B * v2v1[1] - c2c1_B * v3v1[1]) * scale1, - (c3c1_B * v2v1[2] - c2c1_B * v3v1[2]) * scale1); - - VectorSet(B, (-c3c1_T * v2v1[0] + c2c1_T * v3v1[0]) * scale1, - (-c3c1_T * v2v1[1] + c2c1_T * v3v1[1]) * scale1, - (-c3c1_T * v2v1[2] + c2c1_T * v3v1[2]) * scale1); - - // The normal N is calculated as the cross product between T and B - CrossProduct(T, B, N); - -#if 0 - VectorCopy(T, tangent); - VectorCopy(B, bitangent); - VectorCopy(N, normal); -#else - // Calculate the reciprocal value once and for all (to achieve speed) - scale2 = 1.0f / ((T[0] * B[1] * N[2] - T[2] * B[1] * N[0]) + - (B[0] * N[1] * T[2] - B[2] * N[1] * T[0]) + - (N[0] * T[1] * B[2] - N[2] * T[1] * B[0])); - - // Calculate the inverse if the TBN matrix using the formula described in the article. - // We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix - CrossProduct(B, N, C); tangent[0] = C[0] * scale2; - CrossProduct(N, T, C); tangent[1] = -C[0] * scale2; - CrossProduct(T, B, C); tangent[2] = C[0] * scale2; - VectorNormalize(tangent); - - CrossProduct(B, N, C); bitangent[0] = -C[1] * scale2; - CrossProduct(N, T, C); bitangent[1] = C[1] * scale2; - CrossProduct(T, B, C); bitangent[2] = -C[1] * scale2; - VectorNormalize(bitangent); - - CrossProduct(B, N, C); normal[0] = C[2] * scale2; - CrossProduct(N, T, C); normal[1] = -C[2] * scale2; - CrossProduct(T, B, C); normal[2] = C[2] * scale2; - VectorNormalize(normal); -#endif - } -} - - -#ifdef USE_VERT_TANGENT_SPACE -qboolean R_CalcTangentVectors(srfVert_t * dv[3]) -{ - int i; - float bb, s, t; - vec3_t bary; - - - /* calculate barycentric basis for the triangle */ - bb = (dv[1]->st[0] - dv[0]->st[0]) * (dv[2]->st[1] - dv[0]->st[1]) - (dv[2]->st[0] - dv[0]->st[0]) * (dv[1]->st[1] - dv[0]->st[1]); - if(fabs(bb) < 0.00000001f) - return qfalse; - - /* do each vertex */ - for(i = 0; i < 3; i++) - { - // calculate s tangent vector - s = dv[i]->st[0] + 10.0f; - t = dv[i]->st[1]; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - dv[i]->tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(dv[i]->tangent, dv[i]->xyz, dv[i]->tangent); - VectorNormalize(dv[i]->tangent); - - // calculate t tangent vector - s = dv[i]->st[0]; - t = dv[i]->st[1] + 10.0f; - bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb; - bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb; - bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb; - - dv[i]->bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0]; - dv[i]->bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1]; - dv[i]->bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2]; - - VectorSubtract(dv[i]->bitangent, dv[i]->xyz, dv[i]->bitangent); - VectorNormalize(dv[i]->bitangent); - - // debug code - //% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i, - //% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] ); - } - - return qtrue; -} -#endif - - -/* -================= -R_FindSurfaceTriangleWithEdge -Tr3B - recoded from Q2E -================= -*/ -static int R_FindSurfaceTriangleWithEdge(int numTriangles, srfTriangle_t * triangles, int start, int end, int ignore) -{ - srfTriangle_t *tri; - int count, match; - int i; - - count = 0; - match = -1; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - if((tri->indexes[0] == start && tri->indexes[1] == end) || - (tri->indexes[1] == start && tri->indexes[2] == end) || (tri->indexes[2] == start && tri->indexes[0] == end)) - { - if(i != ignore) - { - match = i; - } - - count++; - } - else if((tri->indexes[1] == start && tri->indexes[0] == end) || - (tri->indexes[2] == start && tri->indexes[1] == end) || (tri->indexes[0] == start && tri->indexes[2] == end)) - { - count++; - } - } - - // detect edges shared by three triangles and make them seams - if(count > 2) - { - match = -1; - } - - return match; -} - - -/* -================= -R_CalcSurfaceTriangleNeighbors -Tr3B - recoded from Q2E -================= -*/ -void R_CalcSurfaceTriangleNeighbors(int numTriangles, srfTriangle_t * triangles) -{ - int i; - srfTriangle_t *tri; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - tri->neighbors[0] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[1], tri->indexes[0], i); - tri->neighbors[1] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[2], tri->indexes[1], i); - tri->neighbors[2] = R_FindSurfaceTriangleWithEdge(numTriangles, triangles, tri->indexes[0], tri->indexes[2], i); - } -} - -/* -================= -R_CalcSurfaceTrianglePlanes -================= -*/ -void R_CalcSurfaceTrianglePlanes(int numTriangles, srfTriangle_t * triangles, srfVert_t * verts) -{ - int i; - srfTriangle_t *tri; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - float *v1, *v2, *v3; - vec3_t d1, d2; - - v1 = verts[tri->indexes[0]].xyz; - v2 = verts[tri->indexes[1]].xyz; - v3 = verts[tri->indexes[2]].xyz; - - VectorSubtract(v2, v1, d1); - VectorSubtract(v3, v1, d2); - - CrossProduct(d2, d1, tri->plane); - tri->plane[3] = DotProduct(tri->plane, v1); - } -} - - -/* -================= -R_CullLocalBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullLocalBox(vec3_t localBounds[2]) { -#if 0 - 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 -#else - int j; - vec3_t transformed; - vec3_t v; - vec3_t worldBounds[2]; - - if(r_nocull->integer) - { - return CULL_CLIP; - } - - // transform into world space - ClearBounds(worldBounds[0], worldBounds[1]); - - for(j = 0; j < 8; j++) - { - v[0] = localBounds[j & 1][0]; - v[1] = localBounds[(j >> 1) & 1][1]; - v[2] = localBounds[(j >> 2) & 1][2]; - - R_LocalPointToWorld(v, transformed); - - AddPointToBounds(transformed, worldBounds[0], worldBounds[1]); - } - - return R_CullBox(worldBounds); -#endif -} - -/* -================= -R_CullBox - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -int R_CullBox(vec3_t worldBounds[2]) { - int i; - cplane_t *frust; - qboolean anyClip; - int r, numPlanes; - - numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4; - - // check against frustum planes - anyClip = qfalse; - for(i = 0; i < numPlanes; i++) - { - frust = &tr.viewParms.frustum[i]; - - r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust); - - if(r == 2) - { - // completely outside frustum - return CULL_OUT; - } - if(r == 3) - { - anyClip = qtrue; - } - } - - if(!anyClip) - { - // completely inside frustum - return CULL_IN; - } - - // partially clipped - return CULL_CLIP; -} - -/* -** R_CullLocalPointAndRadius -*/ -int R_CullLocalPointAndRadius( const vec3_t pt, float radius ) -{ - vec3_t transformed; - - R_LocalPointToWorld( pt, transformed ); - - return R_CullPointAndRadius( transformed, radius ); -} - -/* -** R_CullPointAndRadius -*/ -int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frustum, int numPlanes ) -{ - int i; - float dist; - const cplane_t *frust; - qboolean mightBeClipped = qfalse; - - if ( r_nocull->integer ) { - return CULL_CLIP; - } - - // check against frustum planes - for (i = 0 ; i < numPlanes ; i++) - { - frust = &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_CullPointAndRadius -*/ -int R_CullPointAndRadius( const vec3_t pt, float radius ) -{ - return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4); -} - -/* -================= -R_LocalNormalToWorld - -================= -*/ -void R_LocalNormalToWorld (const 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 (const 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 (const 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; - - Matrix16Copy(glMatrix, or->transformMatrix); - 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 R_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_SetupFrustum - -Set up the culling frustum planes for the current view using the results we got from computing the first two rows of -the projection matrix. -================= -*/ -void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep) -{ - vec3_t ofsorigin; - float oppleg, adjleg, length; - int i; - - if(stereoSep == 0 && xmin == -xmax) - { - // symmetric case can be simplified - VectorCopy(dest->or.origin, ofsorigin); - - length = sqrt(xmax * xmax + zProj * zProj); - oppleg = xmax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal); - } - else - { - // In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the - // actual origin that we're rendering so offset the tip of the view pyramid. - VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin); - - oppleg = xmax + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal); - VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal); - - oppleg = xmin + stereoSep; - length = sqrt(oppleg * oppleg + zProj * zProj); - VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal); - VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal); - } - - length = sqrt(ymax * ymax + zProj * zProj); - oppleg = ymax / length; - adjleg = zProj / length; - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal); - VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal); - - VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal); - VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal); - - for (i=0 ; i<4 ; i++) { - dest->frustum[i].type = PLANE_NON_AXIAL; - dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal); - SetPlaneSignbits( &dest->frustum[i] ); - } - - if (zFar != 0.0f) - { - vec3_t farpoint; - - VectorMA(ofsorigin, zFar, dest->or.axis[0], farpoint); - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - - dest->frustum[4].type = PLANE_NON_AXIAL; - dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal); - SetPlaneSignbits( &dest->frustum[4] ); - dest->flags |= VPF_FARPLANEFRUSTUM; - } -} - -/* -=============== -R_SetupProjection -=============== -*/ -void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum) -{ - float xmin, xmax, ymin, ymax; - float width, height, stereoSep = r_stereoSeparation->value; - - /* - * offset the view origin of the viewer for stereo rendering - * by setting the projection matrix appropriately. - */ - - if(stereoSep != 0) - { - if(dest->stereoFrame == STEREO_LEFT) - stereoSep = zProj / stereoSep; - else if(dest->stereoFrame == STEREO_RIGHT) - stereoSep = zProj / -stereoSep; - else - stereoSep = 0; - } - - ymax = zProj * tan(dest->fovY * M_PI / 360.0f); - ymin = -ymax; - - xmax = zProj * tan(dest->fovX * M_PI / 360.0f); - xmin = -xmax; - - width = xmax - xmin; - height = ymax - ymin; - - dest->projectionMatrix[0] = 2 * zProj / width; - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; - dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 * zProj / height; - dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = -1; - dest->projectionMatrix[15] = 0; - - // Now that we have all the data for the projection matrix we can also setup the view frustum. - if(computeFrustum) - R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep); -} - -/* -=============== -R_SetupProjectionZ - -Sets the z-component transformation part in the projection matrix -=============== -*/ -void R_SetupProjectionZ(viewParms_t *dest) -{ - float zNear, zFar, depth; - - zNear = r_znear->value; - zFar = dest->zFar; - - depth = zFar - zNear; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -( zFar + zNear ) / depth; - dest->projectionMatrix[14] = -2 * zFar * zNear / depth; - - if (dest->isPortal) - { - float plane[4]; - float plane2[4]; - vec4_t q, c; - - // transform portal plane into camera space - plane[0] = dest->portalPlane.normal[0]; - plane[1] = dest->portalPlane.normal[1]; - plane[2] = dest->portalPlane.normal[2]; - plane[3] = dest->portalPlane.dist; - - plane2[0] = -DotProduct (dest->or.axis[1], plane); - plane2[1] = DotProduct (dest->or.axis[2], plane); - plane2[2] = -DotProduct (dest->or.axis[0], plane); - plane2[3] = DotProduct (plane, dest->or.origin) - plane[3]; - - // Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping". - // Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html - q[0] = (SGN(plane2[0]) + dest->projectionMatrix[8]) / dest->projectionMatrix[0]; - q[1] = (SGN(plane2[1]) + dest->projectionMatrix[9]) / dest->projectionMatrix[5]; - q[2] = -1.0f; - q[3] = (1.0f + dest->projectionMatrix[10]) / dest->projectionMatrix[14]; - - VectorScale4(plane2, 2.0f / DotProduct4(plane2, q), c); - - dest->projectionMatrix[2] = c[0]; - dest->projectionMatrix[6] = c[1]; - dest->projectionMatrix[10] = c[2] + 1.0f; - dest->projectionMatrix[14] = c[3]; - - } - -} - -/* -=============== -R_SetupProjectionOrtho -=============== -*/ -void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2]) -{ - float xmin, xmax, ymin, ymax, znear, zfar; - //viewParms_t *dest = &tr.viewParms; - int i; - vec3_t pop; - - // Quake3: Projection: - // - // Z X Y Z - // | / | / - // |/ |/ - // Y--+ +--X - - xmin = viewBounds[0][1]; - xmax = viewBounds[1][1]; - ymin = -viewBounds[1][2]; - ymax = -viewBounds[0][2]; - znear = viewBounds[0][0]; - zfar = viewBounds[1][0]; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = 0; - dest->projectionMatrix[12] = (xmax + xmin) / (xmax - xmin); - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = 0; - dest->projectionMatrix[13] = (ymax + ymin) / (ymax - ymin); - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = -2 / (zfar - znear); - dest->projectionMatrix[14] = -(zfar + znear) / (zfar - znear); - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, viewBounds[0][1], dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -viewBounds[1][1], dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, viewBounds[0][2], dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -viewBounds[1][2], dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -viewBounds[1][0], dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (i = 0; i < 5; i++) - { - dest->frustum[i].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[i]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; -} - -/* -================= -R_MirrorPoint -================= -*/ -void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - vec3_t local; - vec3_t transformed; - float d; - - VectorSubtract( in, surface->origin, local ); - - VectorClear( transformed ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(local, surface->axis[i]); - VectorMA( transformed, d, camera->axis[i], transformed ); - } - - VectorAdd( transformed, camera->origin, out ); -} - -void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) { - int i; - float d; - - VectorClear( out ); - for ( i = 0 ; i < 3 ; i++ ) { - d = DotProduct(in, surface->axis[i]); - VectorMA( out, d, camera->axis[i], out ); - } -} - - -/* -============= -R_PlaneForSurface -============= -*/ -void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) { - srfTriangles_t *tri; - srfPoly_t *poly; - srfVert_t *v1, *v2, *v3; - vec4_t plane4; - - if (!surfType) { - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } - switch (*surfType) { - case SF_FACE: - *plane = ((srfSurfaceFace_t *)surfType)->plane; - return; - case SF_TRIANGLES: - tri = (srfTriangles_t *)surfType; - v1 = tri->verts + tri->triangles[0].indexes[0]; - v2 = tri->verts + tri->triangles[0].indexes[1]; - v3 = tri->verts + tri->triangles[0].indexes[2]; - PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - case SF_POLY: - poly = (srfPoly_t *)surfType; - PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz ); - VectorCopy( plane4, plane->normal ); - plane->dist = plane4[3]; - return; - default: - Com_Memset (plane, 0, sizeof(*plane)); - plane->normal[0] = 1; - return; - } -} - -/* -================= -R_GetPortalOrientation - -entityNum is the entity that the portal surface is a part of, which may -be moving and rotating. - -Returns qtrue if it should be mirrored -================= -*/ -qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum, - orientation_t *surface, orientation_t *camera, - vec3_t pvsOrigin, qboolean *mirror ) { - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - vec3_t transformed; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } else { - plane = originalPlane; - } - - VectorCopy( plane.normal, surface->axis[0] ); - PerpendicularVector( surface->axis[1], surface->axis[0] ); - CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] ); - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // get the pvsOrigin from the entity - VectorCopy( e->e.oldorigin, pvsOrigin ); - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) { - VectorScale( plane.normal, plane.dist, surface->origin ); - VectorCopy( surface->origin, camera->origin ); - VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] ); - VectorCopy( surface->axis[1], camera->axis[1] ); - VectorCopy( surface->axis[2], camera->axis[2] ); - - *mirror = qtrue; - return qtrue; - } - - // project the origin onto the surface plane to get - // an origin point we can rotate around - d = DotProduct( e->e.origin, plane.normal ) - plane.dist; - VectorMA( e->e.origin, -d, surface->axis[0], surface->origin ); - - // now get the camera origin and orientation - VectorCopy( e->e.oldorigin, camera->origin ); - AxisCopy( e->e.axis, camera->axis ); - VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] ); - VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] ); - - // optionally rotate - if ( e->e.oldframe ) { - // if a speed is specified - if ( e->e.frame ) { - // continuous rotate - d = (tr.refdef.time/1000.0f) * e->e.frame; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } else { - // bobbing rotate, with skinNum being the rotation offset - d = sin( tr.refdef.time * 0.003f ); - d = e->e.skinNum + d * 4; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - } - else if ( e->e.skinNum ) { - d = e->e.skinNum; - VectorCopy( camera->axis[1], transformed ); - RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d ); - CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] ); - } - *mirror = qfalse; - return qtrue; - } - - // if we didn't locate a portal entity, don't render anything. - // We don't want to just treat it as a mirror, because without a - // portal entity the server won't have communicated a proper entity set - // in the snapshot - - // unfortunately, with local movement prediction it is easily possible - // to see a surface before the server has communicated the matching - // portal surface entity, so we don't want to print anything here... - - //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" ); - - return qfalse; -} - -static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) -{ - int i; - cplane_t originalPlane, plane; - trRefEntity_t *e; - float d; - - // create plane axis for the portal we are seeing - R_PlaneForSurface( drawSurf->surface, &originalPlane ); - - // rotate the plane if necessary - if ( entityNum != REFENTITYNUM_WORLD ) - { - tr.currentEntityNum = entityNum; - tr.currentEntity = &tr.refdef.entities[entityNum]; - - // get the orientation of the entity - R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or ); - - // rotate the plane, but keep the non-rotated version for matching - // against the portalSurface entities - R_LocalNormalToWorld( originalPlane.normal, plane.normal ); - plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin ); - - // translate the original plane - originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); - } - else - { - plane = originalPlane; - } - - // locate the portal entity closest to this plane. - // origin will be the origin of the portal, origin2 will be - // the origin of the camera - for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) - { - e = &tr.refdef.entities[i]; - if ( e->e.reType != RT_PORTALSURFACE ) { - continue; - } - - d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist; - if ( d > 64 || d < -64) { - continue; - } - - // if the entity is just a mirror, don't use as a camera point - if ( e->e.oldorigin[0] == e->e.origin[0] && - e->e.oldorigin[1] == e->e.origin[1] && - e->e.oldorigin[2] == e->e.origin[2] ) - { - return qtrue; - } - - return qfalse; - } - return qfalse; -} - -/* -** SurfIsOffscreen -** -** Determines if a surface is completely offscreen. -*/ -static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) { - float shortest = 100000000; - int entityNum; - int numTriangles; - shader_t *shader; - int fogNum; - int dlighted; - int pshadowed; - vec4_t clip, eye; - int i; - unsigned int pointOr = 0; - unsigned int pointAnd = (unsigned int)~0; - - R_RotateForViewer(); - - R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - RB_BeginSurface( shader, fogNum ); - rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface ); - - assert( tess.numVertexes < 128 ); - - for ( i = 0; i < tess.numVertexes; i++ ) - { - int j; - unsigned int pointFlags = 0; - - R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip ); - - for ( j = 0; j < 3; j++ ) - { - if ( clip[j] >= clip[3] ) - { - pointFlags |= (1 << (j*2)); - } - else if ( clip[j] <= -clip[3] ) - { - pointFlags |= ( 1 << (j*2+1)); - } - } - pointAnd &= pointFlags; - pointOr |= pointFlags; - } - - // trivially reject - if ( pointAnd ) - { - return qtrue; - } - - // determine if this surface is backfaced and also determine the distance - // to the nearest vertex so we can cull based on portal range. Culling - // based on vertex distance isn't 100% correct (we should be checking for - // range to the surface), but it's good enough for the types of portals - // we have in the game right now. - numTriangles = tess.numIndexes / 3; - - for ( i = 0; i < tess.numIndexes; i += 3 ) - { - vec3_t normal; - float len; - - VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal ); - - len = VectorLengthSquared( normal ); // lose the sqrt - if ( len < shortest ) - { - shortest = len; - } - - if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 ) - { - numTriangles--; - } - } - if ( !numTriangles ) - { - return qtrue; - } - - // mirrors can early out at this point, since we don't do a fade over distance - // with them (although we could) - if ( IsMirror( drawSurf, entityNum ) ) - { - return qfalse; - } - - if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) ) - { - return qtrue; - } - - return qfalse; -} - -/* -======================== -R_MirrorViewBySurface - -Returns qtrue if another view has been rendered -======================== -*/ -qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { - vec4_t clipDest[128]; - viewParms_t newParms; - viewParms_t oldParms; - orientation_t surface, camera; - - // don't recursively mirror - if (tr.viewParms.isPortal) { - ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); - return qfalse; - } - - if ( r_noportals->integer || (r_fastsky->integer == 1) ) { - return qfalse; - } - - // trivially reject portal/mirror - if ( SurfIsOffscreen( drawSurf, clipDest ) ) { - return qfalse; - } - - // save old viewParms so we can return to it after the mirror view - oldParms = tr.viewParms; - - newParms = tr.viewParms; - newParms.isPortal = qtrue; - newParms.zFar = 0.0f; - newParms.flags &= ~VPF_FARPLANEFRUSTUM; - if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, - newParms.pvsOrigin, &newParms.isMirror ) ) { - return qfalse; // bad portal, no portalentity - } - - R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); - - VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); - newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); - - R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); - R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); - R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); - - // OPTIMIZE: restrict the viewport on the mirrored view - - // render the mirror view - R_RenderView (&newParms); - - tr.viewParms = oldParms; - - return qtrue; -} - -/* -================= -R_SpriteFogNum - -See if a sprite is inside a fog volume -================= -*/ -int R_SpriteFogNum( trRefEntity_t *ent ) { - int i, j; - fog_t *fog; - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { - return 0; - } - - for ( i = 1 ; i < tr.world->numfogs ; i++ ) { - fog = &tr.world->fogs[i]; - for ( j = 0 ; j < 3 ; j++ ) { - if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) { - break; - } - if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) { - break; - } - } - if ( j == 3 ) { - return i; - } - } - - return 0; -} - -/* -========================================================================================== - -DRAWSURF SORTING - -========================================================================================== -*/ - -/* -=============== -R_Radix -=============== -*/ -static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest ) -{ - int count[ 256 ] = { 0 }; - int index[ 256 ]; - int i; - unsigned char *sortKey = NULL; - unsigned char *end = NULL; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - end = sortKey + ( size * sizeof( drawSurf_t ) ); - for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) ) - ++count[ *sortKey ]; - - index[ 0 ] = 0; - - for( i = 1; i < 256; ++i ) - index[ i ] = index[ i - 1 ] + count[ i - 1 ]; - - sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte; - for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) ) - dest[ index[ *sortKey ]++ ] = source[ i ]; -} - -/* -=============== -R_RadixSort - -Radix sort with 4 byte size buckets -=============== -*/ -static void R_RadixSort( drawSurf_t *source, int size ) -{ - static drawSurf_t scratch[ MAX_DRAWSURFS ]; -#ifdef Q3_LITTLE_ENDIAN - R_Radix( 0, size, source, scratch ); - R_Radix( 1, size, scratch, source ); - R_Radix( 2, size, source, scratch ); - R_Radix( 3, size, scratch, source ); -#else - R_Radix( 3, size, source, scratch ); - R_Radix( 2, size, scratch, source ); - R_Radix( 1, size, source, scratch ); - R_Radix( 0, size, scratch, source ); -#endif //Q3_LITTLE_ENDIAN -} - -//========================================================================================== - -/* -================= -R_AddDrawSurf -================= -*/ -void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, - int fogIndex, int dlightMap, int pshadowMap ) { - int index; - - // instead of checking for overflow, we just mask the index - // so it wraps around - index = tr.refdef.numDrawSurfs & DRAWSURF_MASK; - // the sort data is packed into a single 32 bit value so it can be - // compared quickly during the qsorting process - tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT) - | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) - | ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap; - tr.refdef.drawSurfs[index].surface = surface; - tr.refdef.numDrawSurfs++; -} - -/* -================= -R_DecomposeSort -================= -*/ -void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader, - int *fogNum, int *dlightMap, int *pshadowMap ) { - *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31; - *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ]; - *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK; - *pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1; - *dlightMap = sort & 1; -} - -/* -================= -R_SortDrawSurfs -================= -*/ -void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) { - shader_t *shader; - int fogNum; - int entityNum; - int dlighted; - int pshadowed; - int i; - - //ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs); - - // it is possible for some views to not have any surfaces - if ( numDrawSurfs < 1 ) { - // we still need to add it for hyperspace cases - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // if we overflowed MAX_DRAWSURFS, the drawsurfs - // wrapped around in the buffer and we will be missing - // the first surfaces, not the last ones - if ( numDrawSurfs > MAX_DRAWSURFS ) { - numDrawSurfs = MAX_DRAWSURFS; - } - - // sort the drawsurfs by sort type, then orientation, then shader - R_RadixSort( drawSurfs, numDrawSurfs ); - - // skip pass through drawing if rendering a shadow map - if (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW)) - { - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); - return; - } - - // check for any pass through drawing, which - // may cause another view to be rendered first - for ( i = 0 ; i < numDrawSurfs ; i++ ) { - R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); - - if ( shader->sort > SS_PORTAL ) { - break; - } - - // no shader should ever have this sort type - if ( shader->sort == SS_BAD ) { - ri.Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name ); - } - - // if the mirror was completely clipped away, we may need to check another surface - if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) { - // this is a debug option to see exactly what is being mirrored - if ( r_portalOnly->integer ) { - return; - } - break; // only one mirror view at a time - } - } - - R_AddDrawSurfCmd( drawSurfs, numDrawSurfs ); -} - -static void R_AddEntitySurface (int entityNum) -{ - trRefEntity_t *ent; - shader_t *shader; - - tr.currentEntityNum = entityNum; - - ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum]; - - ent->needDlights = qfalse; - - // preshift the value we are going to OR into the drawsurf sort - tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT; - - // - // the weapon model must be handled special -- - // we don't want the hacked weapon position showing in - // mirrors, because the true body position will already be drawn - // - if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.isPortal - || (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))) ) { - return; - } - - // simple generated models, like sprites and beams, are not culled - switch ( ent->e.reType ) { - case RT_PORTALSURFACE: - break; // don't draw anything - case RT_SPRITE: - case RT_BEAM: - case RT_LIGHTNING: - case RT_RAIL_CORE: - case RT_RAIL_RINGS: - // self blood sprites, talk balloons, etc should not be drawn in the primary - // view. We can't just do this check for all entities, because md3 - // entities may still want to cast shadows from them - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - return; - } - shader = R_GetShaderByHandle( ent->e.customShader ); - R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0 ); - break; - - case RT_MODEL: - // we must set up parts of tr.or for model culling - R_RotateForEntity( ent, &tr.viewParms, &tr.or ); - - tr.currentModel = R_GetModelByHandle( ent->e.hModel ); - if (!tr.currentModel) { - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); - } else { - switch ( tr.currentModel->type ) { - case MOD_MESH: - R_AddMD3Surfaces( ent ); - break; - case MOD_MD4: - R_AddAnimSurfaces( ent ); - break; -#ifdef RAVENMD4 - case MOD_MDR: - R_MDRAddAnimSurfaces( ent ); - break; -#endif - case MOD_IQM: - R_AddIQMSurfaces( ent ); - break; - case MOD_BRUSH: - R_AddBrushModelSurfaces( ent ); - break; - case MOD_BAD: // null model axis - if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) { - break; - } - R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0 ); - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" ); - break; - } - } - break; - default: - ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" ); - } -} - -/* -============= -R_AddEntitySurfaces -============= -*/ -void R_AddEntitySurfaces (void) { - int i; - - if ( !r_drawentities->integer ) { - return; - } - - for ( i = 0; i < tr.refdef.num_entities; i++) - R_AddEntitySurface(i); -} - - -/* -==================== -R_GenerateDrawSurfs -==================== -*/ -void R_GenerateDrawSurfs( void ) { - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - // set the projection matrix with the minimum zfar - // now that we have the world bounded - // this needs to be done before entities are - // added, because they use the projection - // matrix for lod calculation - - // dynamically compute far clip plane distance - if (!(tr.viewParms.flags & VPF_SHADOWMAP)) - { - R_SetFarClip(); - } - - // we know the size of the clipping volume. Now set the rest of the projection matrix. - R_SetupProjectionZ (&tr.viewParms); - - R_AddEntitySurfaces (); -} - -/* -================ -R_DebugPolygon -================ -*/ -void R_DebugPolygon( int color, int numPoints, float *points ) { - // FIXME: implement this -#if 0 - int i; - - GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - // draw solid shade - - qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - - // draw wireframe outline - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - qglDepthRange( 0, 0 ); - qglColor3f( 1, 1, 1 ); - qglBegin( GL_POLYGON ); - for ( i = 0 ; i < numPoints ; i++ ) { - qglVertex3fv( points + i * 3 ); - } - qglEnd(); - qglDepthRange( 0, 1 ); -#endif -} - -/* -==================== -R_DebugGraphics - -Visualization aid for movement clipping debugging -==================== -*/ -void R_DebugGraphics( void ) { - if ( !r_debugSurface->integer ) { - return; - } - - R_IssuePendingRenderCommands(); - - GL_Bind( tr.whiteImage); - GL_Cull( CT_FRONT_SIDED ); - ri.CM_DrawDebugSurface( R_DebugPolygon ); -} - - -/* -================ -R_RenderView - -A view may be either the actual camera view, -or a mirror / remote location -================ -*/ -void R_RenderView (viewParms_t *parms) { - int firstDrawSurf; - - if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) { - return; - } - - tr.viewCount++; - - tr.viewParms = *parms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, qtrue); - - R_GenerateDrawSurfs(); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - // draw main system development information (surface outlines, etc) - R_DebugGraphics(); -} - - -void R_RenderDlightCubemaps(const refdef_t *fd) -{ - int i; - - for (i = 0; i < tr.refdef.num_dlights; i++) - { - viewParms_t shadowParms; - int j; - - // use previous frame to determine visible dlights - if ((1 << i) & tr.refdef.dlightMask) - continue; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qtrue; // because it is - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW; - shadowParms.zFar = tr.refdef.dlights[i].radius; - - VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin ); - - for (j = 0; j < 6; j++) - { - switch(j) - { - case 0: - // -X - VectorSet( shadowParms.or.axis[0], -1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, -1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 1: - // +X - VectorSet( shadowParms.or.axis[0], 1, 0, 0); - VectorSet( shadowParms.or.axis[1], 0, 0, 1); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 2: - // -Y - VectorSet( shadowParms.or.axis[0], 0, -1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, -1); - break; - case 3: - // +Y - VectorSet( shadowParms.or.axis[0], 0, 1, 0); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 0, 1); - break; - case 4: - // -Z - VectorSet( shadowParms.or.axis[0], 0, 0, -1); - VectorSet( shadowParms.or.axis[1], 1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - case 5: - // +Z - VectorSet( shadowParms.or.axis[0], 0, 0, 1); - VectorSet( shadowParms.or.axis[1], -1, 0, 0); - VectorSet( shadowParms.or.axis[2], 0, 1, 0); - break; - } - - R_RenderView(&shadowParms); - R_AddCapShadowmapCmd( i, j ); - } - } -} - - -void R_RenderPshadowMaps(const refdef_t *fd) -{ - viewParms_t shadowParms; - int i; - - // first, make a list of shadows - for ( i = 0; i < tr.refdef.num_entities; i++) - { - trRefEntity_t *ent = &tr.refdef.entities[i]; - - if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW))) - continue; - - //if((ent->e.renderfx & RF_THIRD_PERSON)) - //continue; - - if (ent->e.reType == RT_MODEL) - { - model_t *model = R_GetModelByHandle( ent->e.hModel ); - pshadow_t shadow; - float radius = 0.0f; - float scale = 1.0f; - vec3_t diff; - int j; - - if (!model) - continue; - - if (ent->e.nonNormalizedAxes) - { - scale = VectorLength( ent->e.axis[0] ); - } - - switch (model->type) - { - case MOD_MESH: - { - mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame]; - - radius = frame->radius * scale; - } - break; - - case MOD_MD4: - { - // FIXME: actually calculate the radius and bounds, this is a horrible hack - radius = r_pshadowDist->value / 2.0f; - } - break; -#ifdef RAVENMD4 - case MOD_MDR: - { - // FIXME: never actually tested this - mdrHeader_t *header = model->modelData; - int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] ); - mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame); - - radius = frame->radius; - } - break; -#endif - case MOD_IQM: - { - // FIXME: never actually tested this - iqmData_t *data = model->modelData; - vec3_t diag; - float *framebounds; - - framebounds = data->bounds + 6*ent->e.frame; - VectorSubtract( framebounds+3, framebounds, diag ); - radius = 0.5f * VectorLength( diag ); - } - break; - - default: - break; - } - - if (!radius) - continue; - - // Cull entities that are behind the viewer by more than lightRadius - VectorSubtract(ent->e.origin, fd->vieworg, diff); - if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value) - continue; - - memset(&shadow, 0, sizeof(shadow)); - - shadow.numEntities = 1; - shadow.entityNums[0] = i; - shadow.viewRadius = radius; - shadow.lightRadius = r_pshadowDist->value; - VectorCopy(ent->e.origin, shadow.viewOrigin); - shadow.sort = DotProduct(diff, diff) / (radius * radius); - VectorCopy(ent->e.origin, shadow.entityOrigins[0]); - shadow.entityRadiuses[0] = radius; - - for (j = 0; j < MAX_CALC_PSHADOWS; j++) - { - pshadow_t swap; - - if (j + 1 > tr.refdef.num_pshadows) - { - tr.refdef.num_pshadows = j + 1; - tr.refdef.pshadows[j] = shadow; - break; - } - - // sort shadows by distance from camera divided by radius - // FIXME: sort better - if (tr.refdef.pshadows[j].sort <= shadow.sort) - continue; - - swap = tr.refdef.pshadows[j]; - tr.refdef.pshadows[j] = shadow; - shadow = swap; - } - } - } - - // next, merge touching pshadows - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *ps1 = &tr.refdef.pshadows[i]; - int j; - - for (j = i + 1; j < tr.refdef.num_pshadows; j++) - { - pshadow_t *ps2 = &tr.refdef.pshadows[j]; - int k; - qboolean touch; - - if (ps1->numEntities == 8) - break; - - touch = qfalse; - if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius)) - { - for (k = 0; k < ps1->numEntities; k++) - { - if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius)) - { - touch = qtrue; - break; - } - } - } - - if (touch) - { - vec3_t newOrigin; - float newRadius; - - BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius); - VectorCopy(newOrigin, ps1->viewOrigin); - ps1->viewRadius = newRadius; - - ps1->entityNums[ps1->numEntities] = ps2->entityNums[0]; - VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]); - ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius; - - ps1->numEntities++; - - for (k = j; k < tr.refdef.num_pshadows - 1; k++) - { - tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1]; - } - - j--; - tr.refdef.num_pshadows--; - } - } - } - - // cap number of drawn pshadows - if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS) - { - tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS; - } - - // next, fill up the rest of the shadow info - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - pshadow_t *shadow = &tr.refdef.pshadows[i]; - vec3_t up; - vec3_t ambientLight, directedLight, lightDir; - - VectorSet(lightDir, 0.57735f, 0.57735f, 0.57735f); -#if 1 - R_LightForPoint(shadow->viewOrigin, ambientLight, directedLight, lightDir); - - // sometimes there's no light - if (DotProduct(lightDir, lightDir) < 0.9f) - VectorSet(lightDir, 0.0f, 0.0f, 1.0f); -#endif - - if (shadow->viewRadius * 3.0f > shadow->lightRadius) - { - shadow->lightRadius = shadow->viewRadius * 3.0f; - } - - VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin); - - // make up a projection, up doesn't matter - VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]); - VectorSet(up, 0, 0, -1); - - if ( abs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f ) - { - VectorSet(up, -1, 0, 0); - } - - CrossProduct(shadow->lightViewAxis[0], up, shadow->lightViewAxis[1]); - VectorNormalize(shadow->lightViewAxis[1]); - CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]); - - VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal); - shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin); - shadow->cullPlane.type = PLANE_NON_AXIAL; - SetPlaneSignbits(&shadow->cullPlane); - } - - // next, render shadowmaps - for ( i = 0; i < tr.refdef.num_pshadows; i++) - { - int firstDrawSurf; - pshadow_t *shadow = &tr.refdef.pshadows[i]; - int j; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE ); - } - shadowParms.viewportWidth = PSHADOW_MAP_SIZE; - shadowParms.viewportHeight = PSHADOW_MAP_SIZE; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.pshadowFbos[i]; - - shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW; - shadowParms.zFar = shadow->lightRadius; - - VectorCopy(shadow->lightOrigin, shadowParms.or.origin); - - VectorCopy(shadow->lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(shadow->lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(shadow->lightViewAxis[2], shadowParms.or.axis[2]); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - { - float xmin, xmax, ymin, ymax, znear, zfar; - viewParms_t *dest = &tr.viewParms; - vec3_t pop; - - xmin = ymin = -shadow->viewRadius; - xmax = ymax = shadow->viewRadius; - znear = 0; - zfar = shadow->lightRadius; - - dest->projectionMatrix[0] = 2 / (xmax - xmin); - dest->projectionMatrix[4] = 0; - dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin); - dest->projectionMatrix[12] =0; - - dest->projectionMatrix[1] = 0; - dest->projectionMatrix[5] = 2 / (ymax - ymin); - dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin); // normally 0 - dest->projectionMatrix[13] = 0; - - dest->projectionMatrix[2] = 0; - dest->projectionMatrix[6] = 0; - dest->projectionMatrix[10] = 2 / (zfar - znear); - dest->projectionMatrix[14] = 0; - - dest->projectionMatrix[3] = 0; - dest->projectionMatrix[7] = 0; - dest->projectionMatrix[11] = 0; - dest->projectionMatrix[15] = 1; - - VectorScale(dest->or.axis[1], 1.0f, dest->frustum[0].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[0].normal, pop); - dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal); - - VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[1].normal, pop); - dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal); - - VectorScale(dest->or.axis[2], 1.0f, dest->frustum[2].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[2].normal, pop); - dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal); - - VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal); - VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[3].normal, pop); - dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal); - - VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal); - VectorMA(dest->or.origin, -shadow->lightRadius, dest->frustum[4].normal, pop); - dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal); - - for (j = 0; j < 5; j++) - { - dest->frustum[j].type = PLANE_NON_AXIAL; - SetPlaneSignbits (&dest->frustum[j]); - } - - dest->flags |= VPF_FARPLANEFRUSTUM; - } - - for (j = 0; j < shadow->numEntities; j++) - { - R_AddEntitySurface(shadow->entityNums[j]); - } - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - - if (!glRefConfig.framebufferObject) - R_AddCapShadowmapCmd( i, -1 ); - } - } -} - -static float CalcSplit(float n, float f, float i, float m) -{ - return (n * pow(f / n, i / m) + (f - n) * i / m) / 2.0f; -} - - -void R_RenderSunShadowMaps(const refdef_t *fd, int level) -{ - viewParms_t shadowParms; - vec4_t lightDir, lightCol; - vec3_t lightViewAxis[3]; - vec3_t lightOrigin; - float splitZNear, splitZFar, splitBias; - float viewZNear, viewZFar; - vec3_t lightviewBounds[2]; - qboolean lightViewIndependentOfCameraView = qfalse; - - if (r_forceSun->integer == 2) - { - int scale = 32768; - float angle = (fd->time % scale) / (float)scale * M_PI; - lightDir[0] = cos(angle); - lightDir[1] = sin(35.0f * M_PI / 180.0f); - lightDir[2] = sin(angle) * cos(35.0f * M_PI / 180.0f); - lightDir[3] = 0.0f; - - if (1) //((fd->time % (scale * 2)) < scale) - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f, 0.0f, 1.0f) * 2.0f; - lightCol[3] = 1.0f; - } - else - { - lightCol[0] = - lightCol[1] = - lightCol[2] = CLAMP(sin(angle) * 2.0f * 0.1f, 0.0f, 0.1f); - lightCol[3] = 1.0f; - } - - VectorCopy4(lightDir, tr.refdef.sunDir); - VectorCopy4(lightCol, tr.refdef.sunCol); - VectorScale4(lightCol, 0.2f, tr.refdef.sunAmbCol); - } - else - { - VectorCopy4(tr.refdef.sunDir, lightDir); - } - - viewZNear = r_shadowCascadeZNear->value; - viewZFar = r_shadowCascadeZFar->value; - splitBias = r_shadowCascadeZBias->value; - - switch(level) - { - case 0: - default: - //splitZNear = r_znear->value; - //splitZFar = 256; - splitZNear = viewZNear; - splitZFar = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - break; - case 1: - splitZNear = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias; - splitZFar = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - //splitZNear = 256; - //splitZFar = 896; - break; - case 2: - splitZNear = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias; - splitZFar = viewZFar; - //splitZNear = 896; - //splitZFar = 3072; - break; - } - - VectorCopy(fd->vieworg, lightOrigin); - - - // Make up a projection - VectorScale(lightDir, -1.0f, lightViewAxis[0]); - - if (lightViewIndependentOfCameraView) - { - // Use world up as light view up - VectorSet(lightViewAxis[2], 0, 0, 1); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and left for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[1], lightViewAxis[2]); - } - else - { - // Use camera view up as light view up - VectorCopy(fd->viewaxis[2], lightViewAxis[2]); - } - - // Check if too close to parallel to light direction - if (abs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f) - { - if (lightViewIndependentOfCameraView) - { - // Use world left as light view up - VectorSet(lightViewAxis[2], 0, 1, 0); - } - else if (level == 0) - { - // Level 0 tries to use a diamond texture orientation relative to camera view - // Use halfway between camera view forward and up for light view up - VectorAdd(fd->viewaxis[0], fd->viewaxis[2], lightViewAxis[2]); - } - else - { - // Use camera view left as light view up - VectorCopy(fd->viewaxis[1], lightViewAxis[2]); - } - } - - // clean axes - CrossProduct(lightViewAxis[2], lightViewAxis[0], lightViewAxis[1]); - VectorNormalize(lightViewAxis[1]); - CrossProduct(lightViewAxis[0], lightViewAxis[1], lightViewAxis[2]); - - // Create bounds for light projection using slice of view projection - { - matrix_t lightViewMatrix; - vec4_t point, base, lightViewPoint; - float lx, ly; - - base[3] = 1; - point[3] = 1; - lightViewPoint[3] = 1; - - Matrix16View(lightViewAxis, lightOrigin, lightViewMatrix); - - ClearBounds(lightviewBounds[0], lightviewBounds[1]); - - // add view near plane - lx = splitZNear * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZNear * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZNear, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - - // add view far plane - lx = splitZFar * tan(fd->fov_x * M_PI / 360.0f); - ly = splitZFar * tan(fd->fov_y * M_PI / 360.0f); - VectorMA(fd->vieworg, splitZFar, fd->viewaxis[0], base); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - VectorMA(base, -lx, fd->viewaxis[1], point); - VectorMA(point, -ly, fd->viewaxis[2], point); - Matrix16Transform(lightViewMatrix, point, lightViewPoint); - AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]); - - if (!glRefConfig.depthClamp) - lightviewBounds[0][0] = lightviewBounds[1][0] - 8192; - - // Moving the Light in Texel-Sized Increments - // from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx - // - if (lightViewIndependentOfCameraView) - { - float cascadeBound, worldUnitsPerTexel, invWorldUnitsPerTexel; - - cascadeBound = MAX(lightviewBounds[1][0] - lightviewBounds[0][0], lightviewBounds[1][1] - lightviewBounds[0][1]); - cascadeBound = MAX(cascadeBound, lightviewBounds[1][2] - lightviewBounds[0][2]); - worldUnitsPerTexel = cascadeBound / tr.sunShadowFbo[level]->width; - invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel; - - VectorScale(lightviewBounds[0], invWorldUnitsPerTexel, lightviewBounds[0]); - lightviewBounds[0][0] = floor(lightviewBounds[0][0]); - lightviewBounds[0][1] = floor(lightviewBounds[0][1]); - lightviewBounds[0][2] = floor(lightviewBounds[0][2]); - VectorScale(lightviewBounds[0], worldUnitsPerTexel, lightviewBounds[0]); - - VectorScale(lightviewBounds[1], invWorldUnitsPerTexel, lightviewBounds[1]); - lightviewBounds[1][0] = floor(lightviewBounds[1][0]); - lightviewBounds[1][1] = floor(lightviewBounds[1][1]); - lightviewBounds[1][2] = floor(lightviewBounds[1][2]); - VectorScale(lightviewBounds[1], worldUnitsPerTexel, lightviewBounds[1]); - } - - //ri.Printf(PRINT_ALL, "znear %f zfar %f\n", lightviewBounds[0][0], lightviewBounds[1][0]); - //ri.Printf(PRINT_ALL, "fovx %f fovy %f xmin %f xmax %f ymin %f ymax %f\n", fd->fov_x, fd->fov_y, xmin, xmax, ymin, ymax); - } - - - { - int firstDrawSurf; - - Com_Memset( &shadowParms, 0, sizeof( shadowParms ) ); - - if (glRefConfig.framebufferObject) - { - shadowParms.viewportX = 0; - shadowParms.viewportY = 0; - } - else - { - shadowParms.viewportX = tr.refdef.x; - shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.sunShadowFbo[level]->height ); - } - shadowParms.viewportWidth = tr.sunShadowFbo[level]->width; - shadowParms.viewportHeight = tr.sunShadowFbo[level]->height; - shadowParms.isPortal = qfalse; - shadowParms.isMirror = qfalse; - - shadowParms.fovX = 90; - shadowParms.fovY = 90; - - if (glRefConfig.framebufferObject) - shadowParms.targetFbo = tr.sunShadowFbo[level]; - - shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC; - shadowParms.zFar = lightviewBounds[1][0]; - - VectorCopy(lightOrigin, shadowParms.or.origin); - - VectorCopy(lightViewAxis[0], shadowParms.or.axis[0]); - VectorCopy(lightViewAxis[1], shadowParms.or.axis[1]); - VectorCopy(lightViewAxis[2], shadowParms.or.axis[2]); - - VectorCopy(lightOrigin, shadowParms.pvsOrigin ); - - { - tr.viewCount++; - - tr.viewParms = shadowParms; - tr.viewParms.frameSceneNum = tr.frameSceneNum; - tr.viewParms.frameCount = tr.frameCount; - - firstDrawSurf = tr.refdef.numDrawSurfs; - - tr.viewCount++; - - // set viewParms.world - R_RotateForViewer (); - - R_SetupProjectionOrtho(&tr.viewParms, lightviewBounds); - - R_AddWorldSurfaces (); - - R_AddPolygonSurfaces(); - - R_AddEntitySurfaces (); - - R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf ); - } - - Matrix16Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]); - } -} |