implemented omnidirectional shadowmapping using depth textures (2D, Rect
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 22 Sep 2009 20:18:12 +0000 (20:18 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 22 Sep 2009 20:18:12 +0000 (20:18 +0000)
and Cube texture types supported)
overhauled viewport handling (now has r_refdef.view.viewport),
R_Viewport functions replace GL_SetupView_ functions, R_SetViewport
makes a viewport current

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9219 d7cf8633-e32d-0410-b094-e92efae38249

17 files changed:
cl_screen.c
client.h
gl_backend.c
gl_backend.h
gl_draw.c
gl_rmain.c
gl_rsurf.c
gl_textures.c
glquake.h
model_alias.c
model_brush.c
model_shared.h
r_shadow.c
r_shadow.h
r_textures.h
render.h
vid_shared.c

index 4e5fd3d..6001636 100644 (file)
@@ -1818,12 +1818,14 @@ static float loadingscreenpic_texcoord2f[8];
 
 static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
 {
+       r_viewport_t viewport;
        float x, y;
        // release mouse grab while loading
        if (!vid.fullscreen)
                VID_SetMouse(false, false, false);
        CHECKGLERROR
-       qglViewport(0, 0, vid.width, vid.height);CHECKGLERROR
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, 0, 0, vid.width, vid.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
+       R_SetViewport(&viewport);
        //qglDisable(GL_SCISSOR_TEST);CHECKGLERROR
        //qglDepthMask(1);CHECKGLERROR
        qglColorMask(1,1,1,1);CHECKGLERROR
@@ -1832,7 +1834,6 @@ static void SCR_DrawLoadingScreen_SharedSetup (qboolean clear)
        if (clear)
                qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
        R_Textures_Frame();
-       GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
        R_Mesh_Start();
        R_Mesh_Matrix(&identitymatrix);
        // draw the loading plaque
index 4b84fa2..f6a8a4d 100644 (file)
--- a/client.h
+++ b/client.h
@@ -1425,6 +1425,32 @@ typedef struct r_refdef_stats_s
 }
 r_refdef_stats_t;
 
+typedef enum r_viewport_type_e
+{
+       R_VIEWPORTTYPE_ORTHO,
+       R_VIEWPORTTYPE_PERSPECTIVE,
+       R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP,
+       R_VIEWPORTTYPE_PERSPECTIVECUBESIDE,
+       R_VIEWPORTTYPE_TOTAL
+}
+r_viewport_type_t;
+
+typedef struct r_viewport_s
+{
+       double m[16];
+       matrix4x4_t cameramatrix; // from entity (transforms from camera entity to world)
+       matrix4x4_t viewmatrix; // actual matrix for rendering (transforms to viewspace)
+       matrix4x4_t projectmatrix; // actual projection matrix (transforms from viewspace to screen)
+       int x;
+       int y;
+       int z;
+       int width;
+       int height;
+       int depth;
+       r_viewport_type_t type;
+}
+r_viewport_t;
+
 typedef struct r_refdef_view_s
 {
        // view information (changes multiple times per frame)
@@ -1461,6 +1487,7 @@ typedef struct r_refdef_view_s
        int width;
        int height;
        int depth;
+       r_viewport_t viewport;
 
        // which color components to allow (for anaglyph glasses)
        int colormask[4];
index 1310985..7a0a66d 100644 (file)
@@ -65,6 +65,11 @@ void GL_PrintError(int errornumber, char *filename, int linenumber)
        case GL_TABLE_TOO_LARGE:
                Con_Printf("GL_TABLE_TOO_LARGE at %s:%i\n", filename, linenumber);
                break;
+#endif
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+       case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
+               Con_Printf("GL_INVALID_FRAMEBUFFER_OPERATION at %s:%i\n", filename, linenumber);
+               break;
 #endif
        default:
                Con_Printf("GL UNKNOWN (%i) at %s:%i\n", errornumber, filename, linenumber);
@@ -77,10 +82,9 @@ void GL_PrintError(int errornumber, char *filename, int linenumber)
 
 void SCR_ScreenShot_f (void);
 
-static matrix4x4_t backend_viewmatrix;
+static r_viewport_t backend_viewport;
 static matrix4x4_t backend_modelmatrix;
 static matrix4x4_t backend_modelviewmatrix;
-static matrix4x4_t backend_projectmatrix;
 
 static unsigned int backendunits, backendimageunits, backendarrayunits, backendactive;
 
@@ -272,183 +276,31 @@ void gl_backend_init(void)
 
 void GL_SetMirrorState(qboolean state);
 
-void GL_SetupView_Orientation_Identity (void)
-{
-       backend_viewmatrix = identitymatrix;
-       GL_SetMirrorState(false);
-       memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
-}
-
-void GL_SetupView_Orientation_FromEntity(const matrix4x4_t *matrix)
-{
-       matrix4x4_t tempmatrix, basematrix;
-       Matrix4x4_Invert_Full(&tempmatrix, matrix);
-       Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
-       Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
-       Matrix4x4_Concat(&backend_viewmatrix, &basematrix, &tempmatrix);
-
-       GL_SetMirrorState(v_flipped.integer != 0);
-       if(v_flipped_state)
-       {
-               Matrix4x4_Transpose(&basematrix, &backend_viewmatrix);
-               Matrix4x4_ConcatScale3(&basematrix, -1, 1, 1);
-               Matrix4x4_Transpose(&backend_viewmatrix, &basematrix);
-       }
-
-       //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[2], 1, 0, 0);
-       //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[0], 0, 1, 0);
-       //Matrix4x4_ConcatRotate(&backend_viewmatrix, -angles[1], 0, 0, 1);
-       //Matrix4x4_ConcatTranslate(&backend_viewmatrix, -origin[0], -origin[1], -origin[2]);
-
-       // force an update of the model matrix by copying it off, resetting it, and then calling the R_Mesh_Matrix function with it
-       tempmatrix = backend_modelmatrix;
-       memset(&backend_modelmatrix, 0, sizeof(backend_modelmatrix));
-       R_Mesh_Matrix(&tempmatrix);
-}
-
-static void GL_BuildFrustum(double m[16], double left, double right, double bottom, double top, double nearVal, double farVal)
-{
-       m[0]  = 2 * nearVal / (right - left);
-       m[1]  = 0;
-       m[2]  = 0;
-       m[3]  = 0;
-
-       m[4]  = 0;
-       m[5]  = 2 * nearVal / (top - bottom);
-       m[6]  = 0;
-       m[7]  = 0;
-
-       m[8]  = (right + left) / (right - left);
-       m[9]  = (top + bottom) / (top - bottom);
-       m[10] = - (farVal + nearVal) / (farVal - nearVal);
-       m[11] = -1;
-
-       m[12] = 0;
-       m[13] = 0;
-       m[14] = - 2 * farVal * nearVal / (farVal - nearVal);
-       m[15] = 0;
-}
-
-void GL_SetupView_Mode_Perspective (double frustumx, double frustumy, double zNear, double zFar)
-{
-       double m[16];
-
-       // set up viewpoint
-       CHECKGLERROR
-       qglMatrixMode(GL_PROJECTION);CHECKGLERROR
-       // set view pyramid
-#if 1
-       // avoid glGetDoublev whenever possible, it may stall the render pipeline
-       // in the tested cases (nvidia) no measurable fps difference, but it sure
-       // makes a difference over a network line with GLX
-       GL_BuildFrustum(m, -frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);
-       qglLoadMatrixd(m);CHECKGLERROR
-#else
-       qglLoadIdentity();CHECKGLERROR
-       qglFrustum(-frustumx * zNear, frustumx * zNear, -frustumy * zNear, frustumy * zNear, zNear, zFar);CHECKGLERROR
-       qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
-#endif
-       Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
-       qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
-       GL_SetupView_Orientation_Identity();
-       CHECKGLERROR
-}
-
-void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double frustumx, double frustumy, double zNear)
+void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out)
 {
-       double nudge, m[16];
-
-       // set up viewpoint
-       CHECKGLERROR
-       qglMatrixMode(GL_PROJECTION);CHECKGLERROR
-       qglLoadIdentity();CHECKGLERROR
-       // set view pyramid
-       nudge = 1.0 - 1.0 / (1<<23);
-       m[ 0] = 1.0 / frustumx;
-       m[ 1] = 0;
-       m[ 2] = 0;
-       m[ 3] = 0;
-       m[ 4] = 0;
-       m[ 5] = 1.0 / frustumy;
-       m[ 6] = 0;
-       m[ 7] = 0;
-       m[ 8] = 0;
-       m[ 9] = 0;
-       m[10] = -nudge;
-       m[11] = -1;
-       m[12] = 0;
-       m[13] = 0;
-       m[14] = -2 * zNear * nudge;
-       m[15] = 0;
-       qglLoadMatrixd(m);CHECKGLERROR
-       qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
-       GL_SetupView_Orientation_Identity();
-       CHECKGLERROR
-       Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
-}
-
-static void GL_BuildOrtho(double m[16], double left, double right, double bottom, double top, double zNear, double zFar)
-{
-       m[0]  = 2/(right - left);
-       m[1]  = 0;
-       m[2]  = 0;
-       m[3]  = 0;
-
-       m[4]  = 0;
-       m[5]  = 2/(top - bottom);
-       m[6]  = 0;
-       m[7]  = 0;
-
-       m[8]  = 0;
-       m[9]  = 0;
-       m[10] = -2/(zFar - zNear);
-       m[11] = 0;
-
-       m[12] = - (right + left)/(right - left);
-       m[13] = - (top + bottom)/(top - bottom);
-       m[14] = - (zFar + zNear)/(zFar - zNear);
-       m[15] = 1;
-}
-
-void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
-{
-       double m[16];
-
-       // set up viewpoint
-       CHECKGLERROR
-       qglMatrixMode(GL_PROJECTION);CHECKGLERROR
-#if 1
-       // avoid glGetDoublev whenever possible, it may stall the render pipeline
-       // in the tested cases (nvidia) no measurable fps difference, but it sure
-       // makes a difference over a network line with GLX
-       GL_BuildOrtho(m, x1, x2, y2, y1, zNear, zFar);
-       qglLoadMatrixd(m);CHECKGLERROR
-#else
-       qglLoadIdentity();CHECKGLERROR
-       qglOrtho(x1, x2, y2, y1, zNear, zFar);CHECKGLERROR
-       qglGetDoublev(GL_PROJECTION_MATRIX, m);CHECKGLERROR
-#endif
-       Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, m);
-       qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
-       GL_SetupView_Orientation_Identity();
-       CHECKGLERROR
+       vec4_t temp;
+       float iw;
+       Matrix4x4_Transform4 (&v->viewmatrix, in, temp);
+       Matrix4x4_Transform4 (&v->projectmatrix, temp, out);
+       iw = 1.0f / out[3];
+       out[0] = v->x + (out[0] * iw + 1.0f) * v->width * 0.5f;
+       out[1] = v->y + v->height - (out[1] * iw + 1.0f) * v->height * 0.5f;
+       out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f;
 }
 
-void GL_SetupView_ApplyCustomNearClipPlane(double normalx, double normaly, double normalz, double dist)
+static void R_Viewport_ApplyNearClipPlane(r_viewport_t *v, double normalx, double normaly, double normalz, double dist)
 {
-       double matrix[16];
        double q[4];
        double d;
        float clipPlane[4], v3[3], v4[3];
        float normal[3];
 
-       // This is Olique Depth Projection from http://www.terathon.com/code/oblique.php
-       // modified to fit in this codebase.
+       // This is inspired by Oblique Depth Projection from http://www.terathon.com/code/oblique.php
 
        VectorSet(normal, normalx, normaly, normalz);
-       Matrix4x4_Transform3x3(&backend_viewmatrix, normal, clipPlane);
+       Matrix4x4_Transform3x3(&v->viewmatrix, normal, clipPlane);
        VectorScale(normal, dist, v3);
-       Matrix4x4_Transform(&backend_viewmatrix, v3, v4);
+       Matrix4x4_Transform(&v->viewmatrix, v3, v4);
        // FIXME: LordHavoc: I think this can be done more efficiently somehow but I can't remember the technique
        clipPlane[3] = -DotProduct(v4, clipPlane);
 
@@ -469,28 +321,248 @@ void GL_SetupView_ApplyCustomNearClipPlane(double normalx, double normaly, doubl
        // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
        // transform it into camera space by multiplying it
        // by the inverse of the projection matrix
-       Matrix4x4_ToArrayDoubleGL(&backend_projectmatrix, matrix);
-
-       q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + matrix[8]) / matrix[0];
-       q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + matrix[9]) / matrix[5];
+       q[0] = ((clipPlane[0] < 0.0f ? -1.0f : clipPlane[0] > 0.0f ? 1.0f : 0.0f) + v->m[8]) / v->m[0];
+       q[1] = ((clipPlane[1] < 0.0f ? -1.0f : clipPlane[1] > 0.0f ? 1.0f : 0.0f) + v->m[9]) / v->m[5];
        q[2] = -1.0f;
-       q[3] = (1.0f + matrix[10]) / matrix[14];
+       q[3] = (1.0f + v->m[10]) / v->m[14];
 
        // Calculate the scaled plane vector
        d = 2.0f / DotProduct4(clipPlane, q);
 
        // Replace the third row of the projection matrix
-       matrix[2] = clipPlane[0] * d;
-       matrix[6] = clipPlane[1] * d;
-       matrix[10] = clipPlane[2] * d + 1.0f;
-       matrix[14] = clipPlane[3] * d;
+       v->m[2] = clipPlane[0] * d;
+       v->m[6] = clipPlane[1] * d;
+       v->m[10] = clipPlane[2] * d + 1.0f;
+       v->m[14] = clipPlane[3] * d;
+}
+
+void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double x1, double y1, double x2, double y2, double nearclip, double farclip, const double *nearplane)
+{
+       float left = x1, right = x2, bottom = y2, top = y1, zNear = nearclip, zFar = farclip;
+       memset(v, 0, sizeof(*v));
+       v->type = R_VIEWPORTTYPE_ORTHO;
+       v->cameramatrix = *cameramatrix;
+       v->x = x;
+       v->y = y;
+       v->z = 0;
+       v->width = width;
+       v->height = height;
+       v->depth = 1;
+       v->m[0]  = 2/(right - left);
+       v->m[5]  = 2/(top - bottom);
+       v->m[10] = -2/(zFar - zNear);
+       v->m[12] = - (right + left)/(right - left);
+       v->m[13] = - (top + bottom)/(top - bottom);
+       v->m[14] = - (zFar + zNear)/(zFar - zNear);
+       v->m[15] = 1;
+
+       Matrix4x4_Invert_Full(&v->viewmatrix, &v->cameramatrix);
+       Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
+
+       if (nearplane)
+               R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
+
+#if 0
+       {
+               vec4_t test1;
+               vec4_t test2;
+               Vector4Set(test1, (x1+x2)*0.5f, (y1+y2)*0.5f, 0.0f, 1.0f);
+               R_Viewport_TransformToScreen(v, test1, test2);
+               Con_Printf("%f %f %f -> %f %f %f\n", test1[0], test1[1], test1[2], test2[0], test2[1], test2[2]);
+       }
+#endif
+}
+
+void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double nearclip, double farclip, const double *nearplane)
+{
+       matrix4x4_t tempmatrix, basematrix;
+       memset(v, 0, sizeof(*v));
+       v->type = R_VIEWPORTTYPE_PERSPECTIVE;
+       v->cameramatrix = *cameramatrix;
+       v->x = x;
+       v->y = y;
+       v->z = 0;
+       v->width = width;
+       v->height = height;
+       v->depth = 1;
+       v->m[0]  = 1.0 / frustumx;
+       v->m[5]  = 1.0 / frustumy;
+       v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
+       v->m[11] = -1;
+       v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
+
+       Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
+       Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
+       Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
+       Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
+
+       //FIXME v_flipped_state is evil, this probably screws things up somewhere
+       if(v_flipped_state)
+       {
+               Matrix4x4_Transpose(&basematrix, &v->viewmatrix);
+               Matrix4x4_ConcatScale3(&basematrix, -1, 1, 1);
+               Matrix4x4_Transpose(&v->viewmatrix, &basematrix);
+       }
+
+       Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
 
-       // Load it back into OpenGL
+       if (nearplane)
+               R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
+}
+
+void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double nearclip, const double *nearplane)
+{
+       matrix4x4_t tempmatrix, basematrix;
+       const double nudge = 1.0 - 1.0 / (1<<23);
+       memset(v, 0, sizeof(*v));
+       v->type = R_VIEWPORTTYPE_PERSPECTIVE_INFINITEFARCLIP;
+       v->cameramatrix = *cameramatrix;
+       v->x = x;
+       v->y = y;
+       v->z = 0;
+       v->width = width;
+       v->height = height;
+       v->depth = 1;
+       v->m[ 0] = 1.0 / frustumx;
+       v->m[ 5] = 1.0 / frustumy;
+       v->m[10] = -nudge;
+       v->m[11] = -1;
+       v->m[14] = -2 * nearclip * nudge;
+
+       Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix);
+       Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0);
+       Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1);
+       Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
+
+       //FIXME v_flipped_state is evil, this probably screws things up somewhere
+       if(v_flipped_state)
+       {
+               Matrix4x4_Transpose(&basematrix, &v->viewmatrix);
+               Matrix4x4_ConcatScale3(&basematrix, -1, 1, 1);
+               Matrix4x4_Transpose(&v->viewmatrix, &basematrix);
+       }
+
+       Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
+
+       if (nearplane)
+               R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
+}
+
+float cubeviewmatrix[6][16] =
+{
+       {
+                0, 0,-1, 0,
+                0,-1, 0, 0,
+               -1, 0, 0, 0,
+                0, 0, 0, 1,
+       },
+       {
+                0, 0, 1, 0,
+                0,-1, 0, 0,
+                1, 0, 0, 0,
+                0, 0, 0, 1,
+       },
+       {
+                1, 0, 0, 0,
+                0, 0,-1, 0,
+                0, 1, 0, 0,
+                0, 0, 0, 1,
+       },
+       {
+                1, 0, 0, 0,
+                0, 0, 1, 0,
+                0,-1, 0, 0,
+                0, 0, 0, 1,
+       },
+       {
+                1, 0, 0, 0,
+                0,-1, 0, 0,
+                0, 0,-1, 0,
+                0, 0, 0, 1,
+       },
+       {
+               -1, 0, 0, 0,
+                0,-1, 0, 0,
+                0, 0, 1, 0,
+                0, 0, 0, 1,
+       },
+};
+
+void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane)
+{
+       matrix4x4_t tempmatrix, basematrix;
+       memset(v, 0, sizeof(*v));
+       v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
+       v->cameramatrix = *cameramatrix;
+       v->width = size;
+       v->height = size;
+       v->depth = 1;
+       v->m[0] = v->m[5] = 1.0f;
+       v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
+       v->m[11] = -1;
+       v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
+
+       Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
+       Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
+       Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
+       Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
+
+       if (nearplane)
+               R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
+}
+
+void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane)
+{
+       matrix4x4_t tempmatrix, basematrix;
+       if (border > size - 2)
+               border = size - 2;
+       memset(v, 0, sizeof(*v));
+       v->type = R_VIEWPORTTYPE_PERSPECTIVECUBESIDE;
+       v->cameramatrix = *cameramatrix;
+       v->x = (side & 1) * size;
+       v->y = (side >> 1) * size;
+       v->width = size;
+       v->height = size;
+       v->depth = 1;
+       v->m[0] = v->m[5] = 1.0f * ((float)size - border) / size;
+       v->m[10] = -(farclip + nearclip) / (farclip - nearclip);
+       v->m[11] = -1;
+       v->m[14] = -2 * nearclip * farclip / (farclip - nearclip);
+
+       Matrix4x4_FromArrayFloatGL(&basematrix, cubeviewmatrix[side]);
+       Matrix4x4_Invert_Simple(&tempmatrix, &v->cameramatrix);
+       Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix);
+       Matrix4x4_FromArrayDoubleGL(&v->projectmatrix, v->m);
+
+       if (nearplane)
+               R_Viewport_ApplyNearClipPlane(v, nearplane[0], nearplane[1], nearplane[2], nearplane[3]);
+}
+
+void R_SetViewport(const r_viewport_t *v)
+{
+       float glmatrix[16];
+       backend_viewport = *v;
+
+       CHECKGLERROR
+       qglViewport(v->x, v->y, v->width, v->height);CHECKGLERROR
+
+       // Load the projection matrix into OpenGL
        qglMatrixMode(GL_PROJECTION);CHECKGLERROR
-       qglLoadMatrixd(matrix);CHECKGLERROR
+       qglLoadMatrixd(backend_viewport.m);CHECKGLERROR
        qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
-       CHECKGLERROR
-       Matrix4x4_FromArrayDoubleGL(&backend_projectmatrix, matrix);
+
+       // FIXME: v_flipped_state is evil, this probably breaks somewhere
+       GL_SetMirrorState(v_flipped.integer && v->type != R_VIEWPORTTYPE_ORTHO);
+
+       // directly force an update of the modelview matrix
+       Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
+       Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
+       qglLoadMatrixf(glmatrix);CHECKGLERROR
+}
+
+void R_GetViewport(r_viewport_t *v)
+{
+       *v = backend_viewport;
 }
 
 typedef struct gltextureunit_s
@@ -498,7 +570,7 @@ typedef struct gltextureunit_s
        const void *pointer_texcoord;
        size_t pointer_texcoord_offset;
        int pointer_texcoord_buffer;
-       int t1d, t2d, t3d, tcubemap;
+       int t1d, t2d, t3d, tcubemap, trectangle;
        int arrayenabled;
        unsigned int arraycomponents;
        int rgbscale, alphascale;
@@ -604,6 +676,10 @@ void GL_SetupTextureState(void)
                {
                        qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
                }
+               if (gl_texturerectangle)
+               {
+                       qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
+               }
        }
 
        for (i = 0;i < backendarrayunits;i++)
@@ -627,6 +703,10 @@ void GL_SetupTextureState(void)
                {
                        qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
                }
+               if (gl_texturerectangle)
+               {
+                       qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+               }
                qglMatrixMode(GL_TEXTURE);CHECKGLERROR
                qglLoadIdentity();CHECKGLERROR
                qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
@@ -945,7 +1025,7 @@ void GL_LockArrays(int first, int count)
 void GL_Scissor (int x, int y, int width, int height)
 {
        CHECKGLERROR
-       qglScissor(x, vid.height - (y + height),width,height);
+       qglScissor(x, y,width,height);
        CHECKGLERROR
 }
 
@@ -968,18 +1048,6 @@ void GL_Clear(int mask)
        qglClear(mask);CHECKGLERROR
 }
 
-void GL_TransformToScreen(const vec4_t in, vec4_t out)
-{
-       vec4_t temp;
-       float iw;
-       Matrix4x4_Transform4 (&backend_viewmatrix, in, temp);
-       Matrix4x4_Transform4 (&backend_projectmatrix, temp, out);
-       iw = 1.0f / out[3];
-       out[0] = r_refdef.view.x + (out[0] * iw + 1.0f) * r_refdef.view.width * 0.5f;
-       out[1] = r_refdef.view.y + r_refdef.view.height - (out[1] * iw + 1.0f) * r_refdef.view.height * 0.5f;
-       out[2] = r_refdef.view.z + (out[2] * iw + 1.0f) * r_refdef.view.depth * 0.5f;
-}
-
 // called at beginning of frame
 void R_Mesh_Start(void)
 {
@@ -1362,6 +1430,10 @@ void R_Mesh_Finish(void)
                {
                        qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
                }
+               if (gl_texturerectangle)
+               {
+                       qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
+               }
        }
        for (i = 0;i < backendarrayunits;i++)
        {
@@ -1381,6 +1453,10 @@ void R_Mesh_Finish(void)
                {
                        qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
                }
+               if (gl_texturerectangle)
+               {
+                       qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+               }
                qglTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);CHECKGLERROR
                if (gl_combine.integer)
                {
@@ -1471,12 +1547,12 @@ void R_Mesh_Matrix(const matrix4x4_t *matrix)
 {
        if (memcmp(matrix, &backend_modelmatrix, sizeof(matrix4x4_t)))
        {
-               double glmatrix[16];
+               float glmatrix[16];
                backend_modelmatrix = *matrix;
-               Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewmatrix, matrix);
-               Matrix4x4_ToArrayDoubleGL(&backend_modelviewmatrix, glmatrix);
+               Matrix4x4_Concat(&backend_modelviewmatrix, &backend_viewport.viewmatrix, &backend_modelmatrix);
+               Matrix4x4_ToArrayFloatGL(&backend_modelviewmatrix, glmatrix);
                CHECKGLERROR
-               qglLoadMatrixd(glmatrix);CHECKGLERROR
+               qglLoadMatrixf(glmatrix);CHECKGLERROR
        }
 }
 
@@ -1577,7 +1653,7 @@ void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, co
        }
 }
 
-void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap)
+void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap, int texrectangle)
 {
        gltextureunit_t *unit = gl_state.units + unitnum;
        if (unitnum >= backendimageunits)
@@ -1678,6 +1754,30 @@ void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, in
                unit->tcubemap = texcubemap;
                qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
        }
+       // update rectangle texture binding
+       if (unit->trectangle != texrectangle)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (texrectangle)
+                       {
+                               if (unit->trectangle == 0)
+                               {
+                                       qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                               }
+                       }
+                       else
+                       {
+                               if (unit->trectangle)
+                               {
+                                       qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                               }
+                       }
+               }
+               unit->trectangle = texrectangle;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
 }
 
 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
@@ -1751,6 +1851,20 @@ void R_Mesh_TexBind1D(unsigned int unitnum, int texnum)
                unit->tcubemap = 0;
                qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
        }
+       // update rectangle texture binding
+       if (unit->trectangle)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->trectangle)
+                       {
+                               qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                       }
+               }
+               unit->trectangle = 0;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
 }
 
 void R_Mesh_TexBind(unsigned int unitnum, int texnum)
@@ -1824,6 +1938,20 @@ void R_Mesh_TexBind(unsigned int unitnum, int texnum)
                unit->tcubemap = 0;
                qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
        }
+       // update rectangle texture binding
+       if (unit->trectangle != 0)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->trectangle)
+                       {
+                               qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                       }
+               }
+               unit->trectangle = 0;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
 }
 
 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
@@ -1897,6 +2025,20 @@ void R_Mesh_TexBind3D(unsigned int unitnum, int texnum)
                unit->tcubemap = 0;
                qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
        }
+       // update rectangle texture binding
+       if (unit->trectangle != 0)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->trectangle)
+                       {
+                               qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                       }
+               }
+               unit->trectangle = 0;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
 }
 
 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
@@ -1970,6 +2112,107 @@ void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum)
                unit->tcubemap = texnum;
                qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
        }
+       // update rectangle texture binding
+       if (unit->trectangle != 0)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->trectangle)
+                       {
+                               qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                       }
+               }
+               unit->trectangle = 0;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
+}
+
+void R_Mesh_TexBindRectangle(unsigned int unitnum, int texnum)
+{
+       gltextureunit_t *unit = gl_state.units + unitnum;
+       if (unitnum >= backendimageunits)
+               return;
+       // update 1d texture binding
+       if (unit->t1d)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->t1d)
+                       {
+                               qglDisable(GL_TEXTURE_1D);CHECKGLERROR
+                       }
+               }
+               unit->t1d = 0;
+               qglBindTexture(GL_TEXTURE_1D, unit->t1d);CHECKGLERROR
+       }
+       // update 2d texture binding
+       if (unit->t2d)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->t2d)
+                       {
+                               qglDisable(GL_TEXTURE_2D);CHECKGLERROR
+                       }
+               }
+               unit->t2d = 0;
+               qglBindTexture(GL_TEXTURE_2D, unit->t2d);CHECKGLERROR
+       }
+       // update 3d texture binding
+       if (unit->t3d)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->t3d)
+                       {
+                               qglDisable(GL_TEXTURE_3D);CHECKGLERROR
+                       }
+               }
+               unit->t3d = 0;
+               qglBindTexture(GL_TEXTURE_3D, unit->t3d);CHECKGLERROR
+       }
+       // update cubemap texture binding
+       if (unit->tcubemap != 0)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (unit->tcubemap)
+                       {
+                               qglDisable(GL_TEXTURE_CUBE_MAP_ARB);CHECKGLERROR
+                       }
+               }
+               unit->tcubemap = 0;
+               qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
+       }
+       // update rectangle texture binding
+       if (unit->trectangle != texnum)
+       {
+               GL_ActiveTexture(unitnum);
+               if (unitnum < backendunits)
+               {
+                       if (texnum)
+                       {
+                               if (unit->trectangle == 0)
+                               {
+                                       qglEnable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                               }
+                       }
+                       else
+                       {
+                               if (unit->trectangle)
+                               {
+                                       qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                               }
+                       }
+               }
+               unit->trectangle = texnum;
+               qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+       }
 }
 
 static const double gl_identitymatrix[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
@@ -2076,7 +2319,7 @@ void R_Mesh_TextureState(const rmeshstate_t *m)
        }
 
        for (i = 0;i < backendimageunits;i++)
-               R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i]);
+               R_Mesh_TexBindAll(i, m->tex1d[i], m->tex[i], m->tex3d[i], m->texcubemap[i], m->texrectangle[i]);
        for (i = 0;i < backendarrayunits;i++)
        {
                if (m->pointer_texcoord3f[i])
@@ -2153,6 +2396,17 @@ void R_Mesh_ResetTextureState(void)
                        unit->tcubemap = 0;
                        qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, unit->tcubemap);CHECKGLERROR
                }
+               // update rectangle texture binding
+               if (unit->trectangle)
+               {
+                       GL_ActiveTexture(unitnum);
+                       if (unitnum < backendunits)
+                       {
+                               qglDisable(GL_TEXTURE_RECTANGLE_ARB);CHECKGLERROR
+                       }
+                       unit->trectangle = 0;
+                       qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, unit->trectangle);CHECKGLERROR
+               }
        }
        for (unitnum = 0;unitnum < backendarrayunits;unitnum++)
        {
index 3feb023..ea9d6e6 100644 (file)
@@ -10,12 +10,15 @@ extern unsigned short polygonelements[(POLYGONELEMENTS_MAXPOINTS-2)*3];
 #define QUADELEMENTS_MAXQUADS 128
 extern unsigned short quadelements[QUADELEMENTS_MAXQUADS*6];
 
-void GL_SetupView_Orientation_Identity(void);
-void GL_SetupView_Orientation_FromEntity(const matrix4x4_t *matrix);
-void GL_SetupView_Mode_Perspective(double frustumx, double frustumy, double zNear, double zFar);
-void GL_SetupView_Mode_PerspectiveInfiniteFarClip(double frustumx, double frustumy, double zNear);
-void GL_SetupView_Mode_Ortho(double x1, double y1, double x2, double y2, double zNear, double zFar);
-void GL_SetupView_ApplyCustomNearClipPlane(double normalx, double normaly, double normalz, double dist);
+void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out);
+void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double x1, double y1, double x2, double y2, double zNear, double zFar, const double *nearplane);
+void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double zNear, double zFar, const double *nearplane);
+void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, double frustumx, double frustumy, double zNear, const double *nearplane);
+void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane);
+void R_Viewport_InitRectSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, int border, float nearclip, float farclip, const float *nearplane);
+void R_SetViewport(const r_viewport_t *v);
+void R_GetViewport(r_viewport_t *v);
+
 void GL_BlendFunc(int blendfunc1, int blendfunc2);
 void GL_DepthMask(int state);
 void GL_DepthTest(int state);
@@ -25,7 +28,6 @@ void GL_CullFace(int state);
 void GL_AlphaTest(int state);
 void GL_ColorMask(int r, int g, int b, int a);
 void GL_Color(float cr, float cg, float cb, float ca);
-void GL_TransformToScreen(const vec4_t in, vec4_t out);
 void GL_LockArrays(int first, int count);
 void GL_ActiveTexture(unsigned int num);
 void GL_ClientActiveTexture(unsigned int num);
@@ -49,6 +51,7 @@ typedef struct rmeshstate_s
        int tex[MAX_TEXTUREUNITS];
        int tex3d[MAX_TEXTUREUNITS];
        int texcubemap[MAX_TEXTUREUNITS];
+       int texrectangle[MAX_TEXTUREUNITS];
        // texture combine settings
        int texrgbscale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
        int texalphascale[MAX_TEXTUREUNITS]; // used only if COMBINE is present
@@ -97,13 +100,14 @@ void R_Mesh_ColorPointer(const float *color4f, int bufferobject, size_t bufferof
 // sets the texcoord array pointer for an array unit
 void R_Mesh_TexCoordPointer(unsigned int unitnum, unsigned int numcomponents, const float *texcoord, int bufferobject, size_t bufferoffset);
 // sets all textures bound to an image unit (multiple can be non-zero at once, according to OpenGL rules the highest one overrides the others)
-void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap);
+void R_Mesh_TexBindAll(unsigned int unitnum, int tex1d, int tex2d, int tex3d, int texcubemap, int texrectangle);
 // sets these are like TexBindAll with only one of the texture indices non-zero
 // (binds one texture type and unbinds all other types)
 void R_Mesh_TexBind1D(unsigned int unitnum, int texnum);
 void R_Mesh_TexBind(unsigned int unitnum, int texnum);
 void R_Mesh_TexBind3D(unsigned int unitnum, int texnum);
 void R_Mesh_TexBindCubeMap(unsigned int unitnum, int texnum);
+void R_Mesh_TexBindRectangle(unsigned int unitnum, int texnum);
 // sets the texcoord matrix for a texenv unit
 void R_Mesh_TexMatrix(unsigned int unitnum, const matrix4x4_t *matrix);
 // sets the combine state for a texenv unit
index bb8745b..bea0007 100644 (file)
--- a/gl_draw.c
+++ b/gl_draw.c
@@ -780,13 +780,14 @@ void GL_Draw_Init (void)
 
 void _DrawQ_Setup(void)
 {
+       r_viewport_t viewport;
        if (r_refdef.draw2dstage)
                return;
        r_refdef.draw2dstage = true;
        CHECKGLERROR
-       qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100, NULL);
+       R_SetViewport(&viewport);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
-       GL_SetupView_Mode_Ortho(0, 0, vid_conwidth.integer, vid_conheight.integer, -10, 100);
        qglDepthFunc(GL_LEQUAL);CHECKGLERROR
        qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
        GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
@@ -1380,11 +1381,16 @@ void DrawQ_Line (float width, float x1, float y1, float x2, float y2, float r, f
 
 void DrawQ_SetClipArea(float x, float y, float width, float height)
 {
+       int ix, iy, iw, ih;
        _DrawQ_Setup();
 
        // We have to convert the con coords into real coords
        // OGL uses top to bottom
-       GL_Scissor((int)(0.5 + x * ((float)vid.width / vid_conwidth.integer)), (int)(0.5 + y * ((float) vid.height / vid_conheight.integer)), (int)(width * ((float)vid.width / vid_conwidth.integer)), (int)(height * ((float)vid.height / vid_conheight.integer)));
+       ix = (int)(0.5 + x * ((float)vid.width / vid_conwidth.integer));
+       iy = (int)(0.5 + y * ((float) vid.height / vid_conheight.integer));
+       iw = (int)(width * ((float)vid.width / vid_conwidth.integer));
+       ih = (int)(height * ((float)vid.height / vid_conheight.integer));
+       GL_Scissor(ix, vid.height - iy - ih, iw, ih);
 
        GL_ScissorTest(true);
 }
index 6f6a313..a2b1d33 100644 (file)
@@ -446,6 +446,12 @@ static void R_BuildFogTexture(void)
 static const char *builtinshaderstring =
 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
 "// written by Forest 'LordHavoc' Hale\n"
+"#ifdef USESHADOWMAPRECT\n"
+"#extension GL_ARB_texture_rectangle : enable\n"
+"#endif\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"#extension GL_EXT_gpu_shader4 : enable\n"
+"#endif\n"
 "\n"
 "// common definitions between vertex shader and fragment shader:\n"
 "\n"
@@ -471,6 +477,22 @@ static const char *builtinshaderstring =
 "# endif\n"
 "\n"
 "#else\n"
+"#ifdef MODE_SHOWDEPTH\n"
+"# ifdef VERTEX_SHADER\n"
+"void main(void)\n"
+"{\n"
+"      gl_Position = ftransform();\n"
+"      gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
+"}\n"
+"# endif\n"
+"# ifdef FRAGMENT_SHADER\n"
+"void main(void)\n"
+"{\n"
+"      gl_FragColor = gl_Color;\n"
+"}\n"
+"# endif\n"
+"\n"
+"#else // !MODE_SHOWDEPTH\n"
 "\n"
 "#ifdef MODE_POSTPROCESS\n"
 "# ifdef VERTEX_SHADER\n"
@@ -740,6 +762,35 @@ static const char *builtinshaderstring =
 "uniform sampler2D Texture_Attenuation;\n"
 "uniform samplerCube Texture_Cube;\n"
 "\n"
+"#define showshadowmap 0\n"
+"#define useshadowsamplerrect 0\n"
+"#define useshadowsampler2d 0\n"
+"#define useshadowsamplercube 1\n"
+"\n"
+"#ifdef USESHADOWMAPRECT\n"
+"# if useshadowsamplerrect\n"
+"uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
+"# else\n"
+"uniform sampler2DRect Texture_ShadowMapRect;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAP2D\n"
+"# if useshadowsampler2d\n"
+"uniform sampler2DShadow Texture_ShadowMap2D;\n"
+"# else\n"
+"uniform sampler2D Texture_ShadowMap2D;\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"# if useshadowsamplercube\n"
+"uniform samplerCubeShadow Texture_ShadowMapCube;\n"
+"# else\n"
+"uniform samplerCube Texture_ShadowMapCube;\n"
+"# endif\n"
+"#endif\n"
+"\n"
 "uniform myhalf3 LightColor;\n"
 "uniform myhalf3 AmbientColor;\n"
 "uniform myhalf3 DiffuseColor;\n"
@@ -838,6 +889,176 @@ static const char *builtinshaderstring =
 "}\n"
 "#endif // USEOFFSETMAPPING\n"
 "\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
+"//float ShadowMap_TextureSize = 1024.0;\n"
+"//float ShadowMap_BorderSize = 6.0;\n"
+"//float ShadowMap_NearClip = 0.0001;\n"
+"//float ShadowMap_FarClip = 1.0;\n"
+"//float ShadowMap_Bias = ShadowMap_NearClip * 64.0 / ShadowMap_TextureSize;\n"
+"//vec2 ShadowMap_TextureScale = vec2(0.5, 0.25);\n"
+"//vec4 ShadowMap_Parameters = vec3(1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, 1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, -(ShadowMap_FarClip + ShadowMap_NearClip) / (ShadowMap_FarClip - ShadowMap_NearClip), -2.0 * ShadowMap_NearClip * ShadowMap_FarClip / (ShadowMap_FarClip - ShadowMap_NearClip));\n"
+"uniform float ShadowMap_Bias;\n"
+"uniform vec2 ShadowMap_TextureScale;\n"
+"uniform vec4 ShadowMap_Parameters;\n"
+"#endif\n"
+"\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"vec3 GetShadowMapTC2D(vec3 dir)\n"
+"{\n"
+"      vec3 adir = abs(dir);\n"
+"      vec3 tc;\n"
+"      vec3 offset;\n"
+"# if 1\n"
+"      float d;\n"
+"      if (adir.x > adir.y)\n"
+"      {\n"
+"              if (adir.x > adir.z)\n"
+"              {\n"
+"                      d = 0.5 / adir.x;\n"
+"                      if (dir.x >= 0.0)\n"
+"                      {\n"
+"                              // +X\n"
+"                              tc = vec3(-dir.z, -dir.y, -dir.x);\n"
+"                              offset = vec3(0.5, 0.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -X\n"
+"                              tc = vec3( dir.z, -dir.y,  dir.x);\n"
+"                              offset = vec3(1.5, 0.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"              else\n"
+"              {\n"
+"                      d = 0.5 / adir.z;\n"
+"                      if (dir.z >= 0.0)\n"
+"                      {\n"
+"                              // +Z\n"
+"                              tc = vec3( dir.x, -dir.y, -dir.z);\n"
+"                              offset = vec3(0.5, 2.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Z\n"
+"                              tc = vec3(-dir.x, -dir.y,  dir.z);\n"
+"                              offset = vec3(1.5, 2.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"      }\n"
+"      else\n"
+"      {\n"
+"              if (adir.y > adir.z)\n"
+"              {\n"
+"                      d = 0.5 / adir.y;\n"
+"                      if (dir.y >= 0.0)\n"
+"                      {\n"
+"                              // +Y\n"
+"                              tc = vec3( dir.x,  dir.z, -dir.y);\n"
+"                              offset = vec3(0.5, 1.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Y\n"
+"                              tc = vec3( dir.x, -dir.z, dir.y);\n"
+"                              offset = vec3(1.5, 1.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"              else\n"
+"              {\n"
+"                      d = 0.5 / adir.z;\n"
+"                      if (dir.z >= 0.0)\n"
+"                      {\n"
+"                              // +Z\n"
+"                              tc = vec3(dir.x, -dir.y, -dir.z);\n"
+"                              offset = vec3(0.5, 2.5, 0.5);\n"
+"                      }\n"
+"                      else\n"
+"                      {\n"
+"                              // -Z\n"
+"                              tc = vec3(-dir.x, -dir.y, dir.z);\n"
+"                              offset = vec3(1.5, 2.5, 0.5);\n"
+"                      }\n"
+"              }\n"
+"      }\n"
+"      tc = tc * ShadowMap_Parameters.xyz * d + offset;\n"
+"      tc.xy *= ShadowMap_TextureScale;\n"
+"      tc.z += ShadowMap_Parameters.w * d - ShadowMap_Bias * d;\n"
+"# else\n"
+"      // experimental method by eihrul, needs overhaul\n"
+"      vec3 ma = vec3(0.0, 0.0, 1.0);\n"
+"      if (adir.x > adir.y)\n"
+"      {\n"
+"              if (adir.x > adir.z)\n"
+"                      ma = vec3(1.0, 0.0, 0.0);\n"
+"      }\n"
+"      else if (adir.y > adir.z)\n"
+"              ma = vec3(0.0, 1.0, 0.0);\n"
+"\n"
+"      tc.xy = dir.xy - ma.xy*(dir.xy - dir.z);\n"
+"      tc.xy = (tc.xy/dot(ma, dir))*0.5 + 0.5;\n"
+"      tc.z = dot(ma, adir);\n"
+"      tc.xy = (tc.xy * tcscale + offset) * vec2(0.5, 0.25);\n"
+"# endif\n"
+"      return tc;\n"
+"}\n"
+"\n"
+"#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
+"\n"
+"#ifdef USESHADOWMAPCUBE\n"
+"vec4 GetShadowMapTCCube(vec3 dir)\n"
+"{\n"
+"      vec3 adir = abs(dir);\n"
+"      float sidedist = max(adir.x, max(adir.y, adir.z));\n"
+"      return vec4(dir, 0.5 - 0.5 * (ShadowMap_Parameters.z - (-ShadowMap_Bias + ShadowMap_Parameters.w) / sidedist));\n"
+"}\n"
+"#endif\n"
+"\n"
+"#if !showshadowmap\n"
+"# ifdef USESHADOWMAPRECT\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+"      float f;\n"
+"#  if useshadowsamplerrect\n"
+"      f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAP2D\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
+"      float f;\n"
+"#  if useshadowsampler2d\n"
+"      f = shadow2D(Texture_ShadowMap2D, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"float ShadowMapCompare(vec3 dir)\n"
+"{\n"
+"      // apply depth texture cubemap as light filter\n"
+"      vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
+"      float f;\n"
+"#  if useshadowsamplercube\n"
+"      f = shadowCube(Texture_ShadowMapCube, shadowmaptc).a;\n"
+"#  else\n"
+"      f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
+"#  endif\n"
+"      return f;\n"
+"}\n"
+"# endif\n"
+"#endif\n"
+"\n"
+"\n"
 "#ifdef MODE_WATER\n"
 "\n"
 "// water pass\n"
@@ -946,6 +1167,12 @@ static const char *builtinshaderstring =
 "#  endif\n"
 "# endif\n"
 "\n"
+"#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
+"#if !showshadowmap\n"
+"      color.rgb *= ShadowMapCompare(CubeVector);\n"
+"#endif\n"
+"#endif\n"
+"\n"
 "# ifdef USECUBEFILTER\n"
 "      // apply light cubemap filter\n"
 "      //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
@@ -1099,6 +1326,32 @@ static const char *builtinshaderstring =
 "#endif\n"
 "\n"
 "      gl_FragColor = vec4(color);\n"
+"\n"
+"#if showshadowmap\n"
+"# ifdef USESHADOWMAPRECT\n"
+"#  if useshadowsamplerrect\n"
+"      gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
+"#  else\n"
+"      gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
+"#  endif\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAP2D\n"
+"#  if useshadowsampler2d\n"
+"      gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
+"#  else\n"
+"      gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
+"#  endif\n"
+"# endif\n"
+"\n"
+"# ifdef USESHADOWMAPCUBE\n"
+"#  if useshadowsamplercube\n"
+"      gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
+"#  else\n"
+"      gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
+"#  endif\n"
+"# endif\n"
+"#endif\n"
 "}\n"
 "#endif // !MODE_REFRACTION\n"
 "#endif // !MODE_WATER\n"
@@ -1107,6 +1360,7 @@ static const char *builtinshaderstring =
 "\n"
 "#endif // !MODE_GENERIC\n"
 "#endif // !MODE_POSTPROCESS\n"
+"#endif // !MODE_SHOWDEPTH\n"
 "#endif // !MODE_DEPTH_OR_SHADOW\n"
 ;
 
@@ -1144,8 +1398,11 @@ typedef enum shaderpermutation_e
        SHADERPERMUTATION_GAMMARAMPS = 1<<12, ///< gamma (postprocessing only)
        SHADERPERMUTATION_POSTPROCESSING = 1<<13, ///< user defined postprocessing
        SHADERPERMUTATION_SATURATION = 1<<14, ///< user defined postprocessing
-       SHADERPERMUTATION_LIMIT = 1<<15, ///< size of permutations array
-       SHADERPERMUTATION_COUNT = 15 ///< size of shaderpermutationinfo array
+       SHADERPERMUTATION_SHADOWMAPRECT = 1<<15, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_SHADOWMAPCUBE = 1<<16, ///< (lightsource) use shadowmap cubemap texture as light filter
+       SHADERPERMUTATION_SHADOWMAP2D = 1<<17, ///< (lightsource) use shadowmap rectangle texture as light filter
+       SHADERPERMUTATION_LIMIT = 1<<18, ///< size of permutations array
+       SHADERPERMUTATION_COUNT = 18 ///< size of shaderpermutationinfo array
 }
 shaderpermutation_t;
 
@@ -1167,6 +1424,9 @@ shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
        {"#define USEGAMMARAMPS\n", " gammaramps"},
        {"#define USEPOSTPROCESSING\n", " postprocessing"},
        {"#define USESATURATION\n", " saturation"},
+       {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
+       {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
+       {"#define USESHADOWMAP2D\n", " shadowmap2d"},
 };
 
 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
@@ -1184,6 +1444,7 @@ typedef enum shadermode_e
        SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
        SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
        SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
+       SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
        SHADERMODE_COUNT
 }
 shadermode_t;
@@ -1203,6 +1464,7 @@ shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
        {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
+       {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
 };
 
 typedef struct r_glsl_permutation_s
@@ -1232,6 +1494,9 @@ typedef struct r_glsl_permutation_s
        int loc_Texture_Cube;
        int loc_Texture_Refraction;
        int loc_Texture_Reflection;
+       int loc_Texture_ShadowMapRect;
+       int loc_Texture_ShadowMapCube;
+       int loc_Texture_ShadowMap2D;
        int loc_FogColor;
        int loc_LightPosition;
        int loc_EyePosition;
@@ -1266,6 +1531,9 @@ typedef struct r_glsl_permutation_s
        int loc_ClientTime;
        int loc_PixelSize;
        int loc_Saturation;
+       int loc_ShadowMap_Bias;
+       int loc_ShadowMap_TextureScale;
+       int loc_ShadowMap_Parameters;
 }
 r_glsl_permutation_t;
 
@@ -1393,6 +1661,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
                p->loc_Texture_Attenuation        = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
                p->loc_Texture_Cube               = qglGetUniformLocationARB(p->program, "Texture_Cube");
+               p->loc_Texture_ShadowMapRect      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
+               p->loc_Texture_ShadowMapCube      = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
+               p->loc_Texture_ShadowMap2D        = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
                p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
                p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
                p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
@@ -1427,6 +1698,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
                p->loc_PixelSize                  = qglGetUniformLocationARB(p->program, "PixelSize");
                p->loc_Saturation                 = qglGetUniformLocationARB(p->program, "Saturation");
+               p->loc_ShadowMap_Bias             = qglGetUniformLocationARB(p->program, "ShadowMap_Bias");
+               p->loc_ShadowMap_TextureScale     = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
+               p->loc_ShadowMap_Parameters       = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
                // initialize the samplers to refer to the texture units we use
                if (p->loc_Texture_First           >= 0) qglUniform1iARB(p->loc_Texture_First          , GL20TU_FIRST);
                if (p->loc_Texture_Second          >= 0) qglUniform1iARB(p->loc_Texture_Second         , GL20TU_SECOND);
@@ -1448,6 +1722,9 @@ static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutatio
                if (p->loc_Texture_Cube            >= 0) qglUniform1iARB(p->loc_Texture_Cube           , GL20TU_CUBE);
                if (p->loc_Texture_Refraction      >= 0) qglUniform1iARB(p->loc_Texture_Refraction     , GL20TU_REFRACTION);
                if (p->loc_Texture_Reflection      >= 0) qglUniform1iARB(p->loc_Texture_Reflection     , GL20TU_REFLECTION);
+               if (p->loc_Texture_ShadowMapRect   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect  , GL20TU_SHADOWMAPRECT);
+               if (p->loc_Texture_ShadowMapCube   >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube  , GL20TU_SHADOWMAPCUBE);
+               if (p->loc_Texture_ShadowMap2D     >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D    , GL20TU_SHADOWMAP2D);
                CHECKGLERROR
                if (developer.integer)
                        Con_Printf("GLSL shader %s compiled.\n", permutationname);
@@ -1588,9 +1865,29 @@ void R_SetupDepthOrShadowShader(void)
        }
 }
 
+void R_SetupShowDepthShader(void)
+{
+       if (gl_support_fragment_shader)
+       {
+               if (r_glsl.integer && r_glsl_usegeneric.integer)
+                       R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
+               else if (r_glsl_permutation)
+               {
+                       r_glsl_permutation = NULL;
+                       qglUseProgramObjectARB(0);CHECKGLERROR
+               }
+       }
+}
+
 extern rtexture_t *r_shadow_attenuationgradienttexture;
 extern rtexture_t *r_shadow_attenuation2dtexture;
 extern rtexture_t *r_shadow_attenuation3dtexture;
+extern qboolean r_shadow_usingshadowmaprect;
+extern qboolean r_shadow_usingshadowmapcube;
+extern qboolean r_shadow_usingshadowmap2d;
+extern float r_shadow_shadowmap_bias;
+extern float r_shadow_shadowmap_texturescale[2];
+extern float r_shadow_shadowmap_parameters[4];
 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
 {
        // select a permutation of the lighting shader appropriate to this
@@ -1632,6 +1929,12 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                        permutation |= SHADERPERMUTATION_COLORMAPPING;
                if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
                        permutation |= SHADERPERMUTATION_CONTRASTBOOST;
+               if (r_shadow_usingshadowmaprect)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
+               if (r_shadow_usingshadowmapcube)
+                       permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
+               if (r_shadow_usingshadowmap2d)
+                       permutation |= SHADERPERMUTATION_SHADOWMAP2D;
        }
        else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
        {
@@ -1763,6 +2066,9 @@ void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, f
                // additive passes are only darkened by fog, not tinted
                if (r_glsl_permutation->loc_FogColor >= 0)
                        qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
+               if (r_glsl_permutation->loc_ShadowMap_Bias >= 0) qglUniform1fARB(r_glsl_permutation->loc_ShadowMap_Bias, r_shadow_shadowmap_bias);
+               if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
+               if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
        }
        else
        {
@@ -3161,15 +3467,8 @@ void R_View_Update(void)
 
 void R_SetupView(qboolean allowwaterclippingplane)
 {
-       if (!r_refdef.view.useperspective)
-               GL_SetupView_Mode_Ortho(-r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
-       else if (gl_stencil && r_useinfinitefarclip.integer)
-               GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip);
-       else
-               GL_SetupView_Mode_Perspective(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
-
-       GL_SetupView_Orientation_FromEntity(&r_refdef.view.matrix);
-
+       const double *customclipplane = NULL;
+       double plane[4];
        if (r_refdef.view.useclipplane && allowwaterclippingplane)
        {
                // LordHavoc: couldn't figure out how to make this approach the
@@ -3177,18 +3476,31 @@ void R_SetupView(qboolean allowwaterclippingplane)
                vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
                if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
                        dist = r_refdef.view.clipplane.dist;
-               GL_SetupView_ApplyCustomNearClipPlane(r_refdef.view.clipplane.normal[0], r_refdef.view.clipplane.normal[1], r_refdef.view.clipplane.normal[2], dist);
+               plane[0] = r_refdef.view.clipplane.normal[0];
+               plane[1] = r_refdef.view.clipplane.normal[1];
+               plane[2] = r_refdef.view.clipplane.normal[2];
+               plane[3] = dist;
+               customclipplane = plane;
        }
+
+       if (!r_refdef.view.useperspective)
+               R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
+       else if (gl_stencil && r_useinfinitefarclip.integer)
+               R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
+       else
+               R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
+       R_SetViewport(&r_refdef.view.viewport);
 }
 
 void R_ResetViewRendering2D(void)
 {
+       r_viewport_t viewport;
        DrawQ_Finish();
 
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
-       qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
-       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
+       R_SetViewport(&viewport);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -3217,7 +3529,7 @@ void R_ResetViewRendering3D(void)
        // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
        qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
        R_SetupView(true);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        GL_Color(1, 1, 1, 1);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
@@ -4148,6 +4460,8 @@ R_RenderView
 */
 void R_RenderView(void)
 {
+       if (r_timereport_active)
+               R_TimeReport("start");
        r_frame++; // used only by R_GetCurrentTexture
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 
index 787b280..6943282 100644 (file)
@@ -1059,6 +1059,45 @@ void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, const vec3_t relativelightor
                GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);
 }
 
+void R_Q1BSP_DrawShadowMap(entity_render_t *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
+{
+       dp_model_t *model = ent->model;
+       msurface_t *surface;
+       int modelsurfacelistindex;
+       float projectdistance = relativelightdirection ? lightradius : lightradius + model->radius*2 + r_shadow_projectdistance.value;
+       // check the box in modelspace, it was already checked in worldspace
+       if (!BoxesOverlap(model->normalmins, model->normalmaxs, lightmins, lightmaxs))
+               return;
+       if (model->brush.shadowmesh)
+       {
+               R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
+               for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++)
+               {
+                       surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex];
+                       if (R_GetCurrentTexture(surface->texture)->currentmaterialflags & MATERIALFLAG_NOSHADOW)
+                               continue;
+                       R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
+               }
+               R_Shadow_ShadowMapFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, 0, 0, model->brush.shadowmesh->element3i, numshadowmark, shadowmarklist);
+       }
+       else
+       {
+               projectdistance = lightradius + model->radius*2;
+               R_Shadow_PrepareShadowMark(model->surfmesh.num_triangles);
+               // identify lit faces within the bounding box
+               for (modelsurfacelistindex = 0;modelsurfacelistindex < modelnumsurfaces;modelsurfacelistindex++)
+               {
+                       surface = model->data_surfaces + modelsurfacelist[modelsurfacelistindex];
+                       rsurface.texture = R_GetCurrentTexture(surface->texture);
+                       if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NOSHADOW)
+                               continue;
+                       RSurf_PrepareVerticesForBatch(false, false, 1, &surface);
+                       R_Shadow_MarkVolumeFromBox(surface->num_firsttriangle, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i, relativelightorigin, relativelightdirection, lightmins, lightmaxs, surface->mins, surface->maxs);
+               }
+               R_Shadow_ShadowMapFromList(model->surfmesh.num_vertices, model->surfmesh.num_triangles, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset, model->surfmesh.data_element3i, numshadowmark, shadowmarklist);
+       }
+}
+
 #define BATCHSIZE 1024
 
 static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
@@ -1069,7 +1108,7 @@ static void R_Q1BSP_DrawLight_TransparentCallback(const entity_render_t *ent, co
        // note: in practice this never actually receives batches), oh well
        R_Shadow_RenderMode_Begin();
        R_Shadow_RenderMode_ActiveLight(rtlight);
-       R_Shadow_RenderMode_Lighting(false, true);
+       R_Shadow_RenderMode_Lighting(false, true, false);
        R_Shadow_SetupEntityLight(ent);
        for (i = 0;i < numsurfaces;i = j)
        {
index f86ee1f..53f34c2 100644 (file)
@@ -44,30 +44,38 @@ typedef struct textypeinfo_s
        float glinternalbytesperpixel;
        int glformat;
        int glinternalformat;
+       int gltype;
 }
 textypeinfo_t;
 
-static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 3};
-static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 4};
-static textypeinfo_t textype_palette_compress       = {TEXTYPE_PALETTE, 1, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB};
-static textypeinfo_t textype_palette_alpha_compress = {TEXTYPE_PALETTE, 1, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB};
-static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 3};
-static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 4};
-static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA   , 4, 4, 0.5f, GL_RGBA   , GL_COMPRESSED_RGB_ARB};
-static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA   , 4, 4, 1.0f, GL_RGBA   , GL_COMPRESSED_RGBA_ARB};
-static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 3};
-static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 4};
-static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA   , 4, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB};
-static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA   , 4, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB};
-
-#define GLTEXTURETYPE_1D 0
-#define GLTEXTURETYPE_2D 1
-#define GLTEXTURETYPE_3D 2
-#define GLTEXTURETYPE_CUBEMAP 3
-
-static int gltexturetypeenums[4] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB};
-static int gltexturetypebindingenums[4] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB};
-static int gltexturetypedimensions[4] = {1, 2, 3, 2};
+static textypeinfo_t textype_palette                = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_alpha          = {TEXTYPE_PALETTE, 1, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_compress       = {TEXTYPE_PALETTE, 1, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_palette_alpha_compress = {TEXTYPE_PALETTE, 1, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba                   = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_alpha             = {TEXTYPE_RGBA   , 4, 4, 4.0f, GL_RGBA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_compress          = {TEXTYPE_RGBA   , 4, 4, 0.5f, GL_RGBA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_rgba_alpha_compress    = {TEXTYPE_RGBA   , 4, 4, 1.0f, GL_RGBA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra                   = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 3, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_alpha             = {TEXTYPE_BGRA   , 4, 4, 4.0f, GL_BGRA   , 4, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_compress          = {TEXTYPE_BGRA   , 4, 4, 0.5f, GL_BGRA   , GL_COMPRESSED_RGB_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_bgra_alpha_compress    = {TEXTYPE_BGRA   , 4, 4, 1.0f, GL_BGRA   , GL_COMPRESSED_RGBA_ARB, GL_UNSIGNED_BYTE};
+static textypeinfo_t textype_shadowmap              = {TEXTYPE_SHADOWMAP,4,4, 4.0f, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT32_ARB, GL_UNSIGNED_INT};
+
+typedef enum gltexturetype_e
+{
+       GLTEXTURETYPE_1D,
+       GLTEXTURETYPE_2D,
+       GLTEXTURETYPE_3D,
+       GLTEXTURETYPE_CUBEMAP,
+       GLTEXTURETYPE_RECTANGLE,
+       GLTEXTURETYPE_TOTAL
+}
+gltexturetype_t;
+
+static int gltexturetypeenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_RECTANGLE_ARB};
+static int gltexturetypebindingenums[GLTEXTURETYPE_TOTAL] = {GL_TEXTURE_BINDING_1D, GL_TEXTURE_BINDING_2D, GL_TEXTURE_BINDING_3D, GL_TEXTURE_BINDING_CUBE_MAP_ARB, GL_TEXTURE_BINDING_RECTANGLE_ARB};
+static int gltexturetypedimensions[GLTEXTURETYPE_TOTAL] = {1, 2, 3, 2, 2};
 static int cubemapside[6] =
 {
        GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
@@ -120,10 +128,12 @@ typedef struct gltexture_s
        int sides;
        // bytes per pixel
        int bytesperpixel;
-       // GL_RGB or GL_RGBA
+       // GL_RGB or GL_RGBA or GL_DEPTH_COMPONENT
        int glformat;
        // 3 or 4
        int glinternalformat;
+       // GL_UNSIGNED_BYTE or GL_UNSIGNED_INT or GL_UNSIGNED_SHORT or GL_FLOAT
+       int gltype;
 }
 gltexture_t;
 
@@ -206,6 +216,8 @@ static textypeinfo_t *R_GetTexTypeInfo(textype_t textype, int flags)
                                return &textype_rgba;
                        case TEXTYPE_BGRA:
                                return &textype_bgra;
+                       case TEXTYPE_SHADOWMAP:
+                               return &textype_shadowmap;
                        default:
                                Host_Error("R_GetTexTypeInfo: unknown texture format");
                                return NULL;
@@ -768,6 +780,19 @@ static void GL_SetupTextureParameters(int flags, int texturetype)
                qglTexParameteri(textureenum, GL_TEXTURE_MAG_FILTER, gl_filter_mag);CHECKGLERROR
        }
 
+       if (texturetype == TEXTYPE_SHADOWMAP)
+       {
+#if 1
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);CHECKGLERROR
+#else
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_TEXTURE_COMPARE_FUNC_ARB, GL_ALWAYS);CHECKGLERROR
+               qglTexParameteri(textureenum, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);CHECKGLERROR
+#endif
+       }
+
        CHECKGLERROR
 }
 
@@ -819,13 +844,13 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                switch(glt->texturetype)
                {
                case GLTEXTURETYPE_1D:
-                       qglTexSubImage1D(GL_TEXTURE_1D, 0, fragx, fragwidth, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexSubImage1D(GL_TEXTURE_1D, 0, fragx, fragwidth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        break;
                case GLTEXTURETYPE_2D:
-                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexSubImage2D(GL_TEXTURE_2D, 0, fragx, fragy, fragwidth, fragheight, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        break;
                case GLTEXTURETYPE_3D:
-                       qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexSubImage3D(GL_TEXTURE_3D, 0, fragx, fragy, fragz, fragwidth, fragheight, fragdepth, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        break;
                default:
                        Host_Error("R_Upload: partial update of type other than 1D, 2D, or 3D");
@@ -867,38 +892,38 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                switch(glt->texturetype)
                {
                case GLTEXTURETYPE_1D:
-                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
                                while (width > 1 || height > 1 || depth > 1)
                                {
                                        Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                                       qglTexImage1D(GL_TEXTURE_1D, mip++, glt->glinternalformat, width, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                }
                        }
                        break;
                case GLTEXTURETYPE_2D:
-                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
                                while (width > 1 || height > 1 || depth > 1)
                                {
                                        Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                                       qglTexImage2D(GL_TEXTURE_2D, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                }
                        }
                        break;
                case GLTEXTURETYPE_3D:
-                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                        if (glt->flags & TEXF_MIPMAP)
                        {
                                while (width > 1 || height > 1 || depth > 1)
                                {
                                        Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                        prevbuffer = resizebuffer;
-                                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                                       qglTexImage3D(GL_TEXTURE_3D, mip++, glt->glinternalformat, width, height, depth, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                }
                        }
                        break;
@@ -922,18 +947,21 @@ static void R_Upload(gltexture_t *glt, const unsigned char *data, int fragx, int
                                        prevbuffer = resizebuffer;
                                }
                                mip = 0;
-                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                if (glt->flags & TEXF_MIPMAP)
                                {
                                        while (width > 1 || height > 1 || depth > 1)
                                        {
                                                Image_MipReduce32(prevbuffer, resizebuffer, &width, &height, &depth, 1, 1, 1);
                                                prevbuffer = resizebuffer;
-                                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, GL_UNSIGNED_BYTE, prevbuffer);CHECKGLERROR
+                                               qglTexImage2D(cubemapside[i], mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, prevbuffer);CHECKGLERROR
                                        }
                                }
                        }
                        break;
+               case GLTEXTURETYPE_RECTANGLE:
+                       qglTexImage2D(GL_TEXTURE_RECTANGLE_ARB, mip++, glt->glinternalformat, width, height, 0, glt->glformat, glt->gltype, NULL);CHECKGLERROR
+                       break;
                }
                GL_SetupTextureParameters(glt->flags, glt->texturetype);
        }
@@ -968,6 +996,11 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        if (cls.state == ca_dedicated)
                return NULL;
 
+       if (texturetype == GLTEXTURETYPE_RECTANGLE && !gl_texturerectangle)
+       {
+               Con_Printf ("R_LoadTexture: rectangle texture not supported by driver\n");
+               return NULL;
+       }
        if (texturetype == GLTEXTURETYPE_CUBEMAP && !gl_texturecubemap)
        {
                Con_Printf ("R_LoadTexture: cubemap texture not supported by driver\n");
@@ -1025,6 +1058,8 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
                        }
                }
                break;
+       case TEXTYPE_SHADOWMAP:
+               break;
        default:
                Host_Error("R_LoadTexture: unknown texture type");
        }
@@ -1045,6 +1080,7 @@ static rtexture_t *R_SetupTexture(rtexturepool_t *rtexturepool, const char *iden
        glt->palette = palette;
        glt->glinternalformat = texinfo->glinternalformat;
        glt->glformat = texinfo->glformat;
+       glt->gltype = texinfo->gltype;
        glt->bytesperpixel = texinfo->internalbytesperpixel;
        glt->sides = glt->texturetype == GLTEXTURETYPE_CUBEMAP ? 6 : 1;
        glt->texnum = 0;
@@ -1090,6 +1126,26 @@ rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *ident
        return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, flags, textype, GLTEXTURETYPE_CUBEMAP, data, palette);
 }
 
+rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height)
+{
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_RECTANGLE, NULL, NULL);
+}
+
+rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width)
+{
+       return R_SetupTexture(rtexturepool, identifier, width, width, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+}
+
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height)
+{
+       return R_SetupTexture(rtexturepool, identifier, width, height, 1, 1, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_2D, NULL, NULL);
+}
+
+rtexture_t *R_LoadTextureCubeProjection(rtexturepool_t *rtexturepool, const char *identifier)
+{
+       return R_SetupTexture(rtexturepool, identifier, 2, 2, 1, 6, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP, TEXTYPE_SHADOWMAP, GLTEXTURETYPE_CUBEMAP, NULL, NULL);
+}
+
 int R_TextureHasAlpha(rtexture_t *rt)
 {
        return rt ? (((gltexture_t *)rt)->flags & TEXF_ALPHA) != 0 : false;
index b1fae14..c865060 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -259,6 +259,29 @@ extern int gl_max_anisotropy;
 #define GL_CLIP_PLANE4                    0x3004
 #define GL_CLIP_PLANE5                    0x3005
 
+#define GL_DEPTH_COMPONENT                0x1902
+#define GL_VIEWPORT                       0x0BA2
+#define GL_DRAW_BUFFER                    0x0C01
+#define GL_READ_BUFFER                    0x0C02
+#define GL_LUMINANCE                      0x1909
+#define GL_INTENSITY                      0x8049
+
+#endif
+
+// GL_ARB_depth_texture
+#ifndef GL_DEPTH_COMPOENNT32_ARB
+#define GL_DEPTH_COMPONENT16_ARB          0x81A5
+#define GL_DEPTH_COMPONENT24_ARB          0x81A6
+#define GL_DEPTH_COMPONENT32_ARB          0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB         0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB         0x884B
+#endif
+
+// GL_ARB_shadow
+#ifndef GL_TEXTURE_COMPARE_MODE_ARB
+#define GL_TEXTURE_COMPARE_MODE_ARB       0x884C
+#define GL_TEXTURE_COMPARE_FUNC_ARB       0x884D
+#define GL_COMPARE_R_TO_TEXTURE_ARB       0x884E
 #endif
 
 extern int gl_max_texture_size;
@@ -384,6 +407,27 @@ extern int gl_max_cube_map_texture_size;
 #define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB               0x851C
 #endif
 
+extern int gl_texturerectangle;
+extern int gl_max_rectangle_texture_size;
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB            0x84F5
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB    0x84F6
+#define GL_PROXY_TEXTURE_RECTANGLE_ARB      0x84F7
+#define GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB   0x84F8
+#define GL_SAMPLER_2D_RECT_ARB              0x8B63
+#define GL_SAMPLER_2D_RECT_SHADOW_ARB       0x8B64
+#endif
+
+extern int gl_depthtexture;
+#ifndef GL_DEPTH_COMPONENT16_ARB
+#define GL_DEPTH_COMPONENT16_ARB       0x81A5
+#define GL_DEPTH_COMPONENT24_ARB       0x81A6
+#define GL_DEPTH_COMPONENT32_ARB       0x81A7
+#define GL_TEXTURE_DEPTH_SIZE_ARB      0x884A
+#define GL_DEPTH_TEXTURE_MODE_ARB      0x884B
+#endif
+
+
 extern int gl_dot3arb;
 #ifndef GL_DOT3_RGB_ARB
 #define GL_DOT3_RGB_ARB                                0x86AE
index e0e7869..c25eb73 100644 (file)
@@ -886,6 +886,7 @@ void Mod_IDP0_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1216,6 +1217,7 @@ void Mod_IDP2_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1456,6 +1458,7 @@ void Mod_IDP3_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1669,6 +1672,7 @@ void Mod_ZYMOTICMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -1971,6 +1975,7 @@ void Mod_DARKPLACESMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -2250,6 +2255,7 @@ void Mod_PSKMODEL_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
@@ -2816,6 +2822,7 @@ void Mod_OBJ_Load(dp_model_t *mod, void *buffer, void *bufferend)
        loadmodel->Draw = R_Q1BSP_Draw;
        loadmodel->DrawDepth = R_Q1BSP_DrawDepth;
        loadmodel->DrawDebug = R_Q1BSP_DrawDebug;
+       loadmodel->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        loadmodel->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        loadmodel->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        loadmodel->DrawLight = R_Q1BSP_DrawLight;
index 667bc22..03009dd 100644 (file)
@@ -3487,6 +3487,7 @@ void Mod_Q1BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->DrawDepth = R_Q1BSP_DrawDepth;
        mod->DrawDebug = R_Q1BSP_DrawDebug;
        mod->GetLightInfo = R_Q1BSP_GetLightInfo;
+       mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        mod->DrawLight = R_Q1BSP_DrawLight;
@@ -5940,6 +5941,7 @@ void Mod_Q3BSP_Load(dp_model_t *mod, void *buffer, void *bufferend)
        mod->DrawDepth = R_Q1BSP_DrawDepth;
        mod->DrawDebug = R_Q1BSP_DrawDebug;
        mod->GetLightInfo = R_Q1BSP_GetLightInfo;
+       mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
        mod->CompileShadowVolume = R_Q1BSP_CompileShadowVolume;
        mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
        mod->DrawLight = R_Q1BSP_DrawLight;
index 3ca435b..b33c6e6 100644 (file)
@@ -880,6 +880,8 @@ typedef struct model_s
        void(*DrawDepth)(struct entity_render_s *ent);
        // draw any enabled debugging effects on this model (such as showing triangles, normals, collision brushes...)
        void(*DrawDebug)(struct entity_render_s *ent);
+       // draw depth into a shadowmap
+       void(*DrawShadowMap)(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
        // gathers info on which clusters and surfaces are lit by light, as well as calculating a bounding box
        void(*GetLightInfo)(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs);
        // compile a shadow volume for the model based on light source
@@ -992,6 +994,7 @@ void R_Q1BSP_Draw(struct entity_render_s *ent);
 void R_Q1BSP_DrawDepth(struct entity_render_s *ent);
 void R_Q1BSP_DrawDebug(struct entity_render_s *ent);
 void R_Q1BSP_GetLightInfo(struct entity_render_s *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs);
+void R_Q1BSP_DrawShadowMap(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 void R_Q1BSP_CompileShadowVolume(struct entity_render_s *ent, vec3_t relativelightorigin, vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist);
 void R_Q1BSP_DrawShadowVolume(struct entity_render_s *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs);
 void R_Q1BSP_DrawLight(struct entity_render_s *ent, int numsurfaces, const int *surfacelist, const unsigned char *trispvs);
index 49fc473..cb094dd 100644 (file)
@@ -140,6 +140,8 @@ demonstrated by the game Doom3.
 #include "portals.h"
 #include "image.h"
 
+#define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
+
 extern void R_Shadow_EditLights_Init(void);
 
 typedef enum r_shadow_rendermode_e
@@ -156,6 +158,9 @@ typedef enum r_shadow_rendermode_e
        R_SHADOW_RENDERMODE_LIGHT_GLSL,
        R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
        R_SHADOW_RENDERMODE_VISIBLELIGHTING,
+       R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
+       R_SHADOW_RENDERMODE_SHADOWMAP2D,
+       R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
 }
 r_shadow_rendermode_t;
 
@@ -163,6 +168,19 @@ r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
+qboolean r_shadow_usingshadowmaprect;
+qboolean r_shadow_usingshadowmap2d;
+qboolean r_shadow_usingshadowmapcube;
+float r_shadow_shadowmap_bias;
+float r_shadow_shadowmap_texturescale[2];
+float r_shadow_shadowmap_parameters[4];
+int r_shadow_drawbuffer;
+int r_shadow_readbuffer;
+GLuint r_shadow_fborectangle;
+GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
+GLuint r_shadow_fbo2d;
+int r_shadow_shadowmapmaxsize;
+int r_shadow_lightscissor[4];
 
 int maxshadowtriangles;
 int *shadowelements;
@@ -200,6 +218,12 @@ rtexture_t *r_shadow_attenuationgradienttexture;
 rtexture_t *r_shadow_attenuation2dtexture;
 rtexture_t *r_shadow_attenuation3dtexture;
 rtexture_t *r_shadow_lightcorona;
+rtexture_t *r_shadow_shadowmaprectangletexture;
+rtexture_t *r_shadow_shadowmap2dtexture;
+rtexture_t *r_shadow_shadowmapcubeprojectiontexture;
+rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
+int r_shadow_shadowmapsize; // changes for each light based on distance
+int r_shadow_shadowmaplod; // changes for each light based on distance
 
 // lights are reloaded when this changes
 char r_shadow_mapname[MAX_QPATH];
@@ -235,6 +259,15 @@ cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_comp
 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
+cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
+cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "0", "shadowmap filter modes: 0 = no filtering, 1 = bilinear, 2 = bilinear small blur (fast), 3 = bilinear large blur (slow)"};
+cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
+cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "1024", "shadowmap size limit"};
+cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "8", "shadowmap size bias"};
+cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "1", "shadowmap size scaling parameter"};
+cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "6", "shadowmap size bias for filtering"};
+cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
+cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
@@ -308,6 +341,16 @@ void r_shadow_start(void)
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
+       r_shadow_shadowmaprectangletexture = NULL;
+       memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
+       r_shadow_shadowmapcubeprojectiontexture = NULL;
+       r_shadow_shadowmap2dtexture = NULL;
+       r_shadow_shadowmapmaxsize = 0;
+       r_shadow_shadowmapsize = 0;
+       r_shadow_shadowmaplod = 0;
+       r_shadow_fborectangle = 0;
+       memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
+       r_shadow_fbo2d = 0;
        r_shadow_texturepool = NULL;
        r_shadow_filters_texturepool = NULL;
        R_Shadow_ValidateCvars();
@@ -340,11 +383,35 @@ void r_shadow_start(void)
 
 void r_shadow_shutdown(void)
 {
+       int i;
+       CHECKGLERROR
        R_Shadow_UncompileWorldLights();
+       CHECKGLERROR
        numcubemaps = 0;
        r_shadow_attenuationgradienttexture = NULL;
        r_shadow_attenuation2dtexture = NULL;
        r_shadow_attenuation3dtexture = NULL;
+       r_shadow_shadowmaprectangletexture = NULL;
+       memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
+       r_shadow_shadowmapcubeprojectiontexture = NULL;
+       r_shadow_shadowmap2dtexture = NULL;
+       r_shadow_shadowmapmaxsize = 0;
+       r_shadow_shadowmapsize = 0;
+       r_shadow_shadowmaplod = 0;
+       CHECKGLERROR
+       if (r_shadow_fborectangle)
+               qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
+       r_shadow_fborectangle = 0;
+       CHECKGLERROR
+       for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+               if (r_shadow_fbocubeside[i])
+                       qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
+       memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
+       CHECKGLERROR
+       if (r_shadow_fbo2d)
+               qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
+       r_shadow_fbo2d = 0;
+       CHECKGLERROR
        R_FreeTexturePool(&r_shadow_texturepool);
        R_FreeTexturePool(&r_shadow_filters_texturepool);
        maxshadowtriangles = 0;
@@ -467,6 +534,15 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
        Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
        Cvar_RegisterVariable(&r_shadow_scissor);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
+       Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
        Cvar_RegisterVariable(&r_shadow_culltriangles);
        Cvar_RegisterVariable(&r_shadow_polygonfactor);
        Cvar_RegisterVariable(&r_shadow_polygonoffset);
@@ -1087,6 +1163,34 @@ void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f,
        }
 }
 
+void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
+{
+       int i, tris = nummarktris;
+       int *outelement3i;
+       const int *element;
+       if (!numverts || !nummarktris)
+               return;
+       // make sure shadowelements is big enough for this mesh
+       if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
+               R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
+
+       // gather up the (sparse) triangles into one array
+       outelement3i = shadowelements;
+       for (i = 0;i < nummarktris;i++)
+       {
+               element = elements + marktris[i] * 3;
+               outelement3i[0] = element[0];
+               outelement3i[1] = element[1];
+               outelement3i[2] = element[2];
+               outelement3i += 3;
+       }
+
+       r_refdef.stats.lights_dynamicshadowtriangles += tris;
+       r_refdef.stats.lights_shadowtriangles += tris;
+       R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
+       R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
+}
+
 static void R_Shadow_MakeTextures_MakeCorona(void)
 {
        float dx, dy;
@@ -1179,6 +1283,8 @@ void R_Shadow_ValidateCvars(void)
 
 void R_Shadow_RenderMode_Begin(void)
 {
+       GLint drawbuffer;
+       GLint readbuffer;
        R_Shadow_ValidateCvars();
 
        if (!r_shadow_attenuation2dtexture
@@ -1196,7 +1302,7 @@ void R_Shadow_RenderMode_Begin(void)
        GL_DepthTest(true);
        GL_DepthMask(false);
        GL_Color(0, 0, 0, 1);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
 
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
@@ -1222,6 +1328,12 @@ void R_Shadow_RenderMode_Begin(void)
                r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
        else
                r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
+
+       CHECKGLERROR
+       qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
+       qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
+       r_shadow_drawbuffer = drawbuffer;
+       r_shadow_readbuffer = readbuffer;
 }
 
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
@@ -1236,6 +1348,14 @@ void R_Shadow_RenderMode_Reset(void)
        {
                qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
        }
+       if (gl_support_ext_framebuffer_object)
+       {
+               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
+       }
+       qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
+       qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
+       R_SetViewport(&r_refdef.view.viewport);
+       GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
        R_Mesh_ColorPointer(NULL, 0, 0);
        R_Mesh_ResetTextureState();
        GL_DepthRange(0, 1);
@@ -1252,6 +1372,10 @@ void R_Shadow_RenderMode_Reset(void)
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_BlendFunc(GL_ONE, GL_ZERO);
        R_SetupGenericShader(false);
+       r_shadow_usingshadowmaprect = false;
+       r_shadow_usingshadowmapcube = false;
+       r_shadow_usingshadowmap2d = false;
+       CHECKGLERROR
 }
 
 void R_Shadow_ClearStencil(void)
@@ -1311,7 +1435,192 @@ void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
        }
 }
 
-void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
+void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
+{
+       int i;
+       int status;
+       int maxsize;
+       float nearclip, farclip;
+       r_viewport_t viewport;
+       CHECKGLERROR
+       maxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
+       if (r_shadow_shadowmapmaxsize != maxsize)
+       {
+               r_shadow_shadowmapmaxsize = maxsize;
+
+               if (r_shadow_fborectangle)
+                       qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
+               r_shadow_fborectangle = 0;
+
+               if (r_shadow_fbo2d)
+                       qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
+               r_shadow_fbo2d = 0;
+
+               for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+                       if (r_shadow_fbocubeside[i])
+                               qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
+               memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
+
+               if (r_shadow_shadowmaprectangletexture)
+                       R_FreeTexture(r_shadow_shadowmaprectangletexture);
+               r_shadow_shadowmaprectangletexture = NULL;
+
+               if (r_shadow_shadowmap2dtexture)
+                       R_FreeTexture(r_shadow_shadowmap2dtexture);
+               r_shadow_shadowmap2dtexture = NULL;
+
+               if (r_shadow_shadowmapcubeprojectiontexture)
+                       R_FreeTexture(r_shadow_shadowmapcubeprojectiontexture);
+               r_shadow_shadowmapcubeprojectiontexture = NULL;
+
+               for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+                       if (r_shadow_shadowmapcubetexture[i])
+                               R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
+               memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
+
+               CHECKGLERROR
+       }
+       nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
+       farclip = 1.0f;
+       r_shadow_shadowmap_bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
+       r_shadow_shadowmap_parameters[0] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
+       r_shadow_shadowmap_parameters[1] = 1.0f - r_shadow_shadowmapping_bordersize.value / size;
+       r_shadow_shadowmap_parameters[2] = -(farclip + nearclip) / (farclip - nearclip);
+       r_shadow_shadowmap_parameters[3] = -2.0f * nearclip * farclip / (farclip - nearclip);
+       if (!r_shadow_shadowmapcubeprojectiontexture)
+               r_shadow_shadowmapcubeprojectiontexture = R_LoadTextureCubeProjection(r_shadow_texturepool, "shadowmapcubeprojection");
+       if (r_shadow_shadowmapping.integer == 3)
+       {
+               // complex unrolled cube approach (more flexible)
+               if (!r_shadow_shadowmap2dtexture)
+               {
+#if 1
+                       r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*4);
+                       qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
+#endif
+               }
+               CHECKGLERROR
+               R_Shadow_RenderMode_Reset();
+               if (r_shadow_shadowmap2dtexture)
+               {
+                       // render depth into the fbo, do not render color at all
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
+                       qglDrawBuffer(GL_NONE);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                       {
+                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                       }
+                       R_SetupDepthOrShadowShader();
+               }
+               else
+               {
+                       R_SetupShowDepthShader();
+                       qglClearColor(1,1,1,1);CHECKGLERROR
+               }
+               R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
+               r_shadow_shadowmap_texturescale[0] = (float)size / R_TextureWidth(r_shadow_shadowmap2dtexture);
+               r_shadow_shadowmap_texturescale[1] = (float)size / R_TextureHeight(r_shadow_shadowmap2dtexture);
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
+       }
+       else if (r_shadow_shadowmapping.integer == 2)
+       {
+               // complex unrolled cube approach (more flexible)
+               if (!r_shadow_shadowmaprectangletexture)
+               {
+#if 1
+                       r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*4);
+                       qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
+                       qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
+#endif
+               }
+               CHECKGLERROR
+               R_Shadow_RenderMode_Reset();
+               if (r_shadow_shadowmaprectangletexture)
+               {
+                       // render depth into the fbo, do not render color at all
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
+                       qglDrawBuffer(GL_NONE);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                       {
+                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                       }
+                       R_SetupDepthOrShadowShader();
+               }
+               else
+               {
+                       R_SetupShowDepthShader();
+                       qglClearColor(1,1,1,1);CHECKGLERROR
+               }
+               R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapping_bordersize.integer, nearclip, farclip, NULL);
+               r_shadow_shadowmap_texturescale[0] = size;
+               r_shadow_shadowmap_texturescale[1] = size;
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
+       }
+       else
+       {
+               // simple cube approach
+               if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
+               {
+#if 1
+                       r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size);
+                       qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
+                       for (i = 0;i < 6;i++)
+                       {
+                               qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
+                               qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
+                       }
+#endif
+               }
+               CHECKGLERROR
+               R_Shadow_RenderMode_Reset();
+               if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
+               {
+                       // render depth into the fbo, do not render color at all
+                       qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
+                       qglDrawBuffer(GL_NONE);CHECKGLERROR
+                       qglReadBuffer(GL_NONE);CHECKGLERROR
+                       status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
+                       if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+                       {
+                               Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
+                               Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
+                       }
+                       R_SetupDepthOrShadowShader();
+               }
+               else
+               {
+                       R_SetupShowDepthShader();
+                       qglClearColor(1,1,1,1);CHECKGLERROR
+               }
+               R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
+               r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+               r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
+               r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
+       }
+       CHECKGLERROR
+       R_SetViewport(&viewport);
+       GL_PolygonOffset(0, 0);
+       GL_CullFace(GL_NONE); // quake is backwards
+       GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
+       GL_DepthMask(true);
+       GL_DepthTest(true);
+       qglClearDepth(1);CHECKGLERROR
+       CHECKGLERROR
+       if (clear)
+               qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |  GL_STENCIL_BUFFER_BIT);
+       CHECKGLERROR
+}
+
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
 {
        CHECKGLERROR
        R_Shadow_RenderMode_Reset();
@@ -1333,10 +1642,33 @@ void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent)
        {
                R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
                GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
+               CHECKGLERROR
+               if (shadowmapping)
+               {
+                       if (r_shadow_shadowmapping.integer == 3)
+                       {
+                               r_shadow_usingshadowmap2d = true;
+                               R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
+                               CHECKGLERROR
+                       }
+                       else if (r_shadow_shadowmapping.integer == 2)
+                       {
+                               r_shadow_usingshadowmaprect = true;
+                               R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
+                               CHECKGLERROR
+                       }
+                       else
+                       {
+                               r_shadow_usingshadowmapcube = true;
+                               R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
+                               CHECKGLERROR
+                       }
+               }
        }
        else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
                R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
        GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
+       CHECKGLERROR
 }
 
 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
@@ -1378,7 +1710,7 @@ void R_Shadow_RenderMode_End(void)
        R_Shadow_RenderMode_Reset();
        R_Shadow_RenderMode_ActiveLight(NULL);
        GL_DepthMask(true);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 }
 
@@ -1415,15 +1747,17 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        int sign[8];
        float f;
 
+       r_shadow_lightscissor[0] = r_refdef.view.x;
+       r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
+       r_shadow_lightscissor[2] = r_refdef.view.width;
+       r_shadow_lightscissor[3] = r_refdef.view.height;
+
        if (!r_shadow_scissor.integer)
                return false;
 
        // if view is inside the light box, just say yes it's visible
        if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
-       {
-               GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
                return false;
-       }
 
        x1 = y1 = x2 = y2 = 0;
 
@@ -1471,7 +1805,7 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
        for (i = 0;i < numvertices;i++)
        {
                VectorCopy(vertex[i], v);
-               GL_TransformToScreen(v, v2);
+               R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
                //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
                if (i)
                {
@@ -1505,9 +1839,11 @@ qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
                return true;
 
        // the light area is visible, set up the scissor rectangle
-       GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
-       //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);CHECKGLERROR
-       //qglEnable(GL_SCISSOR_TEST);CHECKGLERROR
+       r_shadow_lightscissor[0] = ix1;
+       r_shadow_lightscissor[1] = vid.height - iy2;
+       r_shadow_lightscissor[2] = ix2 - ix1;
+       r_shadow_lightscissor[3] = iy2 - iy1;
+
        r_refdef.stats.lights_scissored++;
        return false;
 }
@@ -2947,6 +3283,14 @@ void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned
        msurface_t *surface;
 
        RSurf_ActiveWorldEntity();
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
+       {
+               if (r_refdef.scene.worldentity->model)
+                       r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
+               rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
+               return;
+       }
+
        if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
        {
                CHECKGLERROR
@@ -3014,7 +3358,10 @@ void R_Shadow_DrawEntityShadow(entity_render_t *ent)
        relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
        relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
        relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
-       ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+       if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
+               ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
+       else
+               ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
@@ -3064,6 +3411,55 @@ void R_Shadow_DrawEntityLight(entity_render_t *ent)
        rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
 }
 
+/*
+{{  0,   0, 0}, "px",  true,  true,  true},
+{{  0,  90, 0}, "py", false,  true, false},
+{{  0, 180, 0}, "nx", false, false,  true},
+{{  0, 270, 0}, "ny",  true, false, false},
+{{-90, 180, 0}, "pz", false, false,  true},
+{{ 90, 180, 0}, "nz", false, false,  true}
+*/
+
+static const double shadowviewmat16[6][4][4] =
+{
+       {
+               {-1,  0,  0, 0},
+               { 0, -1,  0, 0},
+               { 0,  0,  1, 0},
+               { 0,  0,  0, 1},
+       },
+       {
+               { 0, -1,  0, 0},
+               {-1,  0,  0, 0},
+               { 0,  0,  1, 0},
+               { 0,  0,  0, 1},
+       },
+       {
+               {-1,  0,  0, 0},
+               { 0, -1,  0, 0},
+               { 0,  0,  1, 0},
+               { 0,  0,  0, 1},
+       },
+       {
+               { 0, -1,  0, 0},
+               {-1,  0,  0, 0},
+               { 0,  0,  1, 0},
+               { 0,  0,  0, 1},
+       },
+       {
+               { 0,  0,  1, 0},
+               { 0, -1,  0, 0},
+               { 1,  0,  0, 0},
+               { 0,  0,  0, 1},
+       },
+       {
+               { 0,  0, -1, 0},
+               { 0, -1,  0, 0},
+               {-1,  0,  0, 0},
+               { 0,  0,  0, 1},
+       },
+};
+
 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
 {
        int i;
@@ -3079,6 +3475,10 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
        static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
        static entity_render_t *shadowentities[MAX_EDICTS];
        static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
+       vec3_t nearestpoint;
+       vec_t distance;
+       qboolean castshadows;
+       int lodlinear;
 
        // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
        // skip lights that are basically invisible (color 0 0 0)
@@ -3266,7 +3666,98 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                        R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
        }
 
-       if (gl_stencil && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
+       if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
+       {
+               // optionally draw the illuminated areas
+               // for performance analysis by level designers
+               R_Shadow_RenderMode_VisibleLighting(false, false);
+               if (numsurfaces)
+                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i]);
+               for (i = 0;i < numlightentities_noselfshadow;i++)
+                       R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
+       }
+
+       castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
+
+       nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
+       nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
+       nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
+       distance = VectorDistance(nearestpoint, r_refdef.view.origin);
+       lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
+       lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
+
+       if (castshadows && r_shadow_shadowmapping.integer/* && r_glsl.integer && gl_support_fragment_shader*/)
+       {
+               int side;
+               int size;
+
+               r_shadow_shadowmaplod = 0;
+               for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
+                       if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
+                               r_shadow_shadowmaplod = i;
+
+               size = lodlinear;
+               if (r_shadow_shadowmapping.integer == 1)
+                       size = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) >> r_shadow_shadowmaplod;
+               size = bound(1, size, 2048);
+
+               Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
+
+               // render shadow casters into 6 sided depth texture
+               for (side = 0;side < 6;side++)
+               {
+                       R_Shadow_RenderMode_ShadowMap(side, true, size);
+                       if (numsurfaces)
+                               R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
+                       for (i = 0;i < numshadowentities;i++)
+                               R_Shadow_DrawEntityShadow(shadowentities[i]);
+               }
+
+               if (numlightentities_noselfshadow)
+               {
+                       // render lighting using the depth texture as shadowmap
+                       // draw lighting in the unmasked areas
+                       R_Shadow_RenderMode_Lighting(false, false, true);
+                       for (i = 0;i < numlightentities_noselfshadow;i++)
+                               R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
+               }
+
+               // render shadow casters into 6 sided depth texture
+               for (side = 0;side < 6;side++)
+               {
+                       R_Shadow_RenderMode_ShadowMap(side, false, size);
+                       for (i = 0;i < numshadowentities_noselfshadow;i++)
+                               R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
+#if 1
+                       if (r_shadow_shadowmapping.integer == 3)
+                       {
+                               int w = R_TextureWidth(r_shadow_shadowmap2dtexture);
+                               int h = R_TextureHeight(r_shadow_shadowmap2dtexture);
+                               static int once = true;
+                               if (once)
+                               {
+                                       unsigned char *blah = Z_Malloc(w*h*4);
+                                       qglReadPixels(0, 0, w, h, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, blah);CHECKGLERROR
+                                       FS_WriteFile("testshadowmap.bin", blah, w*h*4);
+                                       Z_Free(blah);
+                               }
+                               once = false;
+                       }
+#endif
+               }
+
+               // render lighting using the depth texture as shadowmap
+               // draw lighting in the unmasked areas
+               R_Shadow_RenderMode_Lighting(false, false, true);
+               // draw lighting in the unmasked areas
+               if (numsurfaces)
+                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
+               for (i = 0;i < numlightentities;i++)
+                       R_Shadow_DrawEntityLight(lightentities[i]);
+       }
+       else if (castshadows && gl_stencil)
        {
                // draw stencil shadow volumes to mask off pixels that are in shadow
                // so that they won't receive lighting
@@ -3278,7 +3769,7 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                if (numlightentities_noselfshadow)
                {
                        // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(true, false);
+                       R_Shadow_RenderMode_Lighting(true, false, false);
                        for (i = 0;i < numlightentities_noselfshadow;i++)
                                R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
 
@@ -3297,22 +3788,11 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                if (numsurfaces + numlightentities)
                {
                        // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(true, false);
+                       R_Shadow_RenderMode_Lighting(true, false, false);
                        if (numsurfaces)
                                R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
                        for (i = 0;i < numlightentities;i++)
                                R_Shadow_DrawEntityLight(lightentities[i]);
-
-                       // optionally draw the illuminated areas
-                       // for performance analysis by level designers
-                       if (r_showlighting.integer && r_refdef.view.showdebug)
-                       {
-                               R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
-                               if (numsurfaces)
-                                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
-                               for (i = 0;i < numlightentities;i++)
-                                       R_Shadow_DrawEntityLight(lightentities[i]);
-                       }
                }
        }
        else
@@ -3320,26 +3800,13 @@ void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
                if (numsurfaces + numlightentities)
                {
                        // draw lighting in the unmasked areas
-                       R_Shadow_RenderMode_Lighting(false, false);
+                       R_Shadow_RenderMode_Lighting(false, false, false);
                        if (numsurfaces)
                                R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
                        for (i = 0;i < numlightentities;i++)
                                R_Shadow_DrawEntityLight(lightentities[i]);
                        for (i = 0;i < numlightentities_noselfshadow;i++)
                                R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
-
-                       // optionally draw the illuminated areas
-                       // for performance analysis by level designers
-                       if (r_showlighting.integer && r_refdef.view.showdebug)
-                       {
-                               R_Shadow_RenderMode_VisibleLighting(false, false);
-                               if (numsurfaces)
-                                       R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
-                               for (i = 0;i < numlightentities;i++)
-                                       R_Shadow_DrawEntityLight(lightentities[i]);
-                               for (i = 0;i < numlightentities_noselfshadow;i++)
-                                       R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
-                       }
                }
        }
 }
@@ -3400,12 +3867,13 @@ void R_DrawModelShadows(void)
        vec3_t relativeshadowmins, relativeshadowmaxs;
        vec3_t tmp, shadowdir;
        float vertex3f[12];
+       r_viewport_t viewport;
 
        if (!r_drawentities.integer || !gl_stencil)
                return;
 
        CHECKGLERROR
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
 
        r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
 
@@ -3492,8 +3960,9 @@ void R_DrawModelShadows(void)
        vertex3f[9] = 0;vertex3f[10] = 1;vertex3f[11] = 0;
 
        // set up ortho view for rendering this pass
-       GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
-       GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
+       R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
+       R_SetViewport(&viewport);
+       GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
        GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
        GL_ScissorTest(true);
        R_Mesh_Matrix(&identitymatrix);
@@ -3518,8 +3987,8 @@ void R_DrawModelShadows(void)
        // apply the blend to the shadowed areas
        R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
 
-       // restoring the perspective view is done by R_RenderScene
-       //R_SetupView(true);
+       // restore the viewport
+       R_SetViewport(&r_refdef.view.viewport);
 
        // restore other state to normal
        R_Shadow_RenderMode_End();
index 895a355..7056331 100644 (file)
@@ -39,13 +39,14 @@ extern cvar_t gl_ext_stenciltwoside;
 
 void R_Shadow_Init(void);
 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs);
+void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris);
 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs);
 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject);
 void R_Shadow_RenderMode_Begin(void);
 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight);
 void R_Shadow_RenderMode_Reset(void);
 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass);
-void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent);
+void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping);
 void R_Shadow_RenderMode_VisibleShadowVolumes(void);
 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent);
 void R_Shadow_RenderMode_End(void);
index 3af696e..e2f5d5a 100644 (file)
@@ -33,6 +33,8 @@ typedef enum textype_e
        TEXTYPE_RGBA,
        // 32bit BGRA (preferred format due to faster uploads on most hardware)
        TEXTYPE_BGRA,
+       // 32bit S8D24 (24bit depth, 8bit stencil unused)
+       TEXTYPE_SHADOWMAP,
 }
 textype_t;
 
@@ -77,6 +79,10 @@ rtexture_t *R_LoadTexture1D(rtexturepool_t *rtexturepool, const char *identifier
 rtexture_t *R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette);
 rtexture_t *R_LoadTexture3D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, int depth, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette);
 rtexture_t *R_LoadTextureCubeMap(rtexturepool_t *rtexturepool, const char *identifier, int width, const unsigned char *data, textype_t textype, int flags, const unsigned int *palette);
+rtexture_t *R_LoadTextureShadowMapRectangle(rtexturepool_t *rtexturepool, const char *identifier, int width, int height);
+rtexture_t *R_LoadTextureShadowMapCube(rtexturepool_t *rtexturepool, const char *identifier, int width);
+rtexture_t *R_LoadTextureShadowMap2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height);
+rtexture_t *R_LoadTextureCubeProjection(rtexturepool_t *rtexturepool, const char *identifier);
 
 // free a texture
 void R_FreeTexture(rtexture_t *rt);
index d01a870..b893fff 100644 (file)
--- a/render.h
+++ b/render.h
@@ -408,12 +408,16 @@ typedef enum gl20_texunit_e
        // conflicts with lightmap/deluxemap
        GL20TU_ATTENUATION = 9,
        GL20TU_CUBE = 10,
+       GL20TU_SHADOWMAPRECT = 11,
+       GL20TU_SHADOWMAPCUBE = 11,
+       GL20TU_SHADOWMAP2D = 11,
 }
 gl20_texunit;
 
 void R_SetupGenericShader(qboolean usetexture);
 void R_SetupGenericTwoTextureShader(int texturemode);
 void R_SetupDepthOrShadowShader(void);
+void R_SetupShowDepthShader(void);
 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass);
 
 typedef struct r_waterstate_waterplane_s
index debd52e..68428f3 100644 (file)
@@ -20,6 +20,7 @@ float in_windowmouse_x, in_windowmouse_y;
 int gl_max_texture_size = 0;
 int gl_max_3d_texture_size = 0;
 int gl_max_cube_map_texture_size = 0;
+int gl_max_rectangle_texture_size = 0;
 // GL_ARB_multitexture
 int gl_textureunits = 1;
 // GL_ARB_texture_env_combine or GL_EXT_texture_env_combine
@@ -34,10 +35,14 @@ int gl_stencil = false;
 int gl_texture3d = false;
 // GL_ARB_texture_cubemap
 int gl_texturecubemap = false;
+// GL_ARB_texture_rectangle
+int gl_texturerectangle = false;
 // GL_ARB_texture_non_power_of_two
 int gl_support_arb_texture_non_power_of_two = false;
 // GL_ARB_texture_env_dot3
 int gl_dot3arb = false;
+// GL_ARB_depth_texture
+int gl_depthtexture = false;
 // GL_SGIS_texture_edge_clamp
 int gl_support_clamptoedge = false;
 // GL_EXT_texture_filter_anisotropic
@@ -823,8 +828,10 @@ void VID_CheckExtensions(void)
        gl_supportslockarrays = false;
        gl_texture3d = false;
        gl_texturecubemap = false;
+       gl_texturerectangle = false;
        gl_support_arb_texture_non_power_of_two = false;
        gl_dot3arb = false;
+       gl_depthtexture = false;
        gl_support_clamptoedge = false;
        gl_support_anisotropy = false;
        gl_max_anisotropy = 1;
@@ -877,6 +884,10 @@ void VID_CheckExtensions(void)
 // COMMANDLINEOPTION: GL: -nocubemap disables GL_ARB_texture_cube_map (required for bumpmapping)
        if ((gl_texturecubemap = GL_CheckExtension("GL_ARB_texture_cube_map", NULL, "-nocubemap", false)))
                qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &gl_max_cube_map_texture_size);
+// COMMANDLINEOPTION: GL: -norectangle disables GL_ARB_texture_rectangle (required for bumpmapping)
+       if ((gl_texturerectangle = GL_CheckExtension("GL_ARB_texture_rectangle", NULL, "-norectangle", false)))
+               qglGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &gl_max_rectangle_texture_size);
+       gl_depthtexture = GL_CheckExtension("GL_ARB_depth_texture", NULL, "-nodepthtexture", false);
 // COMMANDLINEOPTION: GL: -notexturecompression disables GL_ARB_texture_compression (which saves video memory if it is supported, but can also degrade image quality, see gl_texturecompression cvar documentation for more information)
        gl_support_texture_compression = GL_CheckExtension("GL_ARB_texture_compression", texturecompressionfuncs, "-notexturecompression", false);
 // COMMANDLINEOPTION: GL: -nocva disables GL_EXT_compiled_vertex_array (renders faster)