From 02064cb9589d2bd1b63131e2a3912496df147bf8 Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 22 Sep 2009 20:18:12 +0000 Subject: [PATCH] implemented omnidirectional shadowmapping using depth textures (2D, Rect 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 --- cl_screen.c | 5 +- client.h | 27 ++ gl_backend.c | 654 ++++++++++++++++++++++++++++++++++--------------- gl_backend.h | 20 +- gl_draw.c | 12 +- gl_rmain.c | 346 ++++++++++++++++++++++++-- gl_rsurf.c | 41 +++- gl_textures.c | 122 ++++++--- glquake.h | 44 ++++ model_alias.c | 7 + model_brush.c | 2 + model_shared.h | 3 + r_shadow.c | 557 +++++++++++++++++++++++++++++++++++++---- r_shadow.h | 3 +- r_textures.h | 6 + render.h | 4 + vid_shared.c | 11 + 17 files changed, 1556 insertions(+), 308 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index 4e5fd3de..60016365 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -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 diff --git a/client.h b/client.h index 4b84fa2c..f6a8a4d6 100644 --- 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]; diff --git a/gl_backend.c b/gl_backend.c index 1310985a..7a0a66d6 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -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++) { diff --git a/gl_backend.h b/gl_backend.h index 3feb0230..ea9d6e67 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -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 diff --git a/gl_draw.c b/gl_draw.c index bb8745bd..bea00075 100644 --- 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); } diff --git a/gl_rmain.c b/gl_rmain.c index 6f6a3139..a2b1d330 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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 diff --git a/gl_rsurf.c b/gl_rsurf.c index 787b280f..6943282e 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -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) { diff --git a/gl_textures.c b/gl_textures.c index f86ee1f6..53f34c2d 100644 --- a/gl_textures.c +++ b/gl_textures.c @@ -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; diff --git a/glquake.h b/glquake.h index b1fae147..c8650608 100644 --- 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 diff --git a/model_alias.c b/model_alias.c index e0e78692..c25eb73d 100644 --- a/model_alias.c +++ b/model_alias.c @@ -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; diff --git a/model_brush.c b/model_brush.c index 667bc22a..03009ddf 100644 --- a/model_brush.c +++ b/model_brush.c @@ -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; diff --git a/model_shared.h b/model_shared.h index 3ca435b2..b33c6e6f 100644 --- a/model_shared.h +++ b/model_shared.h @@ -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); diff --git a/r_shadow.c b/r_shadow.c index 49fc4738..cb094ddc 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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(); diff --git a/r_shadow.h b/r_shadow.h index 895a3558..70563316 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -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); diff --git a/r_textures.h b/r_textures.h index 3af696e4..e2f5d5a4 100644 --- a/r_textures.h +++ b/r_textures.h @@ -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); diff --git a/render.h b/render.h index d01a8709..b893fff9 100644 --- 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 diff --git a/vid_shared.c b/vid_shared.c index debd52ec..68428f3e 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -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) -- 2.39.2