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
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
}
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)
int width;
int height;
int depth;
+ r_viewport_t viewport;
// which color components to allow (for anaglyph glasses)
int colormask[4];
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);
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;
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);
// 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
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;
{
qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
}
+ if (gl_texturerectangle)
+ {
+ qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
+ }
}
for (i = 0;i < backendarrayunits;i++)
{
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
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
}
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)
{
{
qglBindTexture(GL_TEXTURE_CUBE_MAP_ARB, 0);CHECKGLERROR
}
+ if (gl_texturerectangle)
+ {
+ qglBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);CHECKGLERROR
+ }
}
for (i = 0;i < backendarrayunits;i++)
{
{
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)
{
{
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
}
}
}
}
-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)
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)
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)
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)
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)
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};
}
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])
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++)
{
#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);
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);
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
// 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
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
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);
}
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"
"# 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"
"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"
"}\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"
"# 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"
"#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"
"\n"
"#endif // !MODE_GENERIC\n"
"#endif // !MODE_POSTPROCESS\n"
+"#endif // !MODE_SHOWDEPTH\n"
"#endif // !MODE_DEPTH_OR_SHADOW\n"
;
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;
{"#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
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;
{"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
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;
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;
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");
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);
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);
}
}
+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
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)
{
// 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
{
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
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);
// 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);
*/
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
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)
// 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)
{
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,
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;
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;
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
}
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");
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;
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);
}
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");
}
}
break;
+ case TEXTYPE_SHADOWMAP:
+ break;
default:
Host_Error("R_LoadTexture: unknown texture type");
}
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;
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;
#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;
#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
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;
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;
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;
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;
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;
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;
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;
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;
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;
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
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);
#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
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;
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;
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];
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)"};
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();
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;
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);
}
}
+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;
void R_Shadow_RenderMode_Begin(void)
{
+ GLint drawbuffer;
+ GLint readbuffer;
R_Shadow_ValidateCvars();
if (!r_shadow_attenuation2dtexture
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;
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)
{
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);
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)
}
}
-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();
{
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)
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;
}
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;
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)
{
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;
}
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
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
}
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;
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)
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
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]);
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
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]);
- }
}
}
}
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;
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);
// 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();
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);
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;
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);
// 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
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
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
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;
// 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)