summaryrefslogtreecommitdiff
path: root/src/rend2/tr_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rend2/tr_main.c')
-rw-r--r--src/rend2/tr_main.c2882
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]);
- }
-}