implemented scissor rect clipping of lights in realtime lighting mode
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 28 Oct 2002 09:17:44 +0000 (09:17 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Mon, 28 Oct 2002 09:17:44 +0000 (09:17 +0000)
DP is no longer fillrate limited on my GF4 at 640x480 :)

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

gl_backend.c
gl_backend.h
gl_rmain.c
glquake.h
r_shadow.c
r_shadow.h
vid_shared.c

index d735341..8f681d2 100644 (file)
@@ -80,6 +80,7 @@ static matrix4x4_t backend_viewmatrix;
 static matrix4x4_t backend_modelmatrix;
 static matrix4x4_t backend_modelviewmatrix;
 static matrix4x4_t backend_glmodelviewmatrix;
 static matrix4x4_t backend_modelmatrix;
 static matrix4x4_t backend_modelviewmatrix;
 static matrix4x4_t backend_glmodelviewmatrix;
+static matrix4x4_t backend_projectmatrix;
 
 static int backendunits, backendactive;
 static qbyte *varray_bcolor;
 
 static int backendunits, backendactive;
 static qbyte *varray_bcolor;
@@ -289,6 +290,22 @@ void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, dou
        qglLoadMatrixd(m);
        qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
        GL_SetupView_Orientation_Identity();
        qglLoadMatrixd(m);
        qglMatrixMode(GL_MODELVIEW);CHECKGLERROR
        GL_SetupView_Orientation_Identity();
+       backend_projectmatrix.m[0][0] = m[0];
+       backend_projectmatrix.m[1][0] = m[1];
+       backend_projectmatrix.m[2][0] = m[2];
+       backend_projectmatrix.m[3][0] = m[3];
+       backend_projectmatrix.m[0][1] = m[4];
+       backend_projectmatrix.m[1][1] = m[5];
+       backend_projectmatrix.m[2][1] = m[6];
+       backend_projectmatrix.m[3][1] = m[7];
+       backend_projectmatrix.m[0][2] = m[8];
+       backend_projectmatrix.m[1][2] = m[9];
+       backend_projectmatrix.m[2][2] = m[10];
+       backend_projectmatrix.m[3][2] = m[11];
+       backend_projectmatrix.m[0][3] = m[12];
+       backend_projectmatrix.m[1][3] = m[13];
+       backend_projectmatrix.m[2][3] = m[14];
+       backend_projectmatrix.m[3][3] = m[15];
 }
 
 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
 }
 
 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar)
@@ -447,6 +464,18 @@ void GL_Color(float cr, float cg, float cb, float ca)
        qglColor4f(cr, cg, cb, ca);
 }
 
        qglColor4f(cr, cg, cb, ca);
 }
 
+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.x + (out[0] * iw + 1.0f) * r_refdef.width * 0.5f;
+       out[1] = r_refdef.y + (out[1] * iw + 1.0f) * r_refdef.height * 0.5f;
+       out[2] = out[2] * iw;
+}
+
 // called at beginning of frame
 void R_Mesh_Start(void)
 {
 // called at beginning of frame
 void R_Mesh_Start(void)
 {
index 40bb6ce..f26fa65 100644 (file)
@@ -17,6 +17,7 @@ void GL_SetupView_Mode_PerspectiveInfiniteFarClip (double fovx, double fovy, dou
 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar);
 void GL_UseColorArray(void);
 void GL_Color(float cr, float cg, float cb, float ca);
 void GL_SetupView_Mode_Ortho (double x1, double y1, double x2, double y2, double zNear, double zFar);
 void GL_UseColorArray(void);
 void GL_Color(float cr, float cg, float cb, float ca);
+void GL_TransformToScreen(const vec4_t in, vec4_t out);
 
 extern cvar_t gl_lockarrays;
 
 
 extern cvar_t gl_lockarrays;
 
index 7ba8402..24c9baa 100644 (file)
@@ -865,6 +865,16 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                                if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
                        }
                }
                                if (clipmaxs[2] < leaf->maxs[2]) clipmaxs[2] = leaf->maxs[2];
                        }
                }
+               if (clipmins[0] < wl->mins[0]) clipmins[0] = wl->mins[0];
+               if (clipmins[1] < wl->mins[1]) clipmins[1] = wl->mins[1];
+               if (clipmins[2] < wl->mins[2]) clipmins[2] = wl->mins[2];
+               if (clipmaxs[0] > wl->maxs[0]) clipmaxs[0] = wl->maxs[0];
+               if (clipmaxs[1] > wl->maxs[1]) clipmaxs[1] = wl->maxs[1];
+               if (clipmaxs[2] > wl->maxs[2]) clipmaxs[2] = wl->maxs[2];
+
+               if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, wl->origin, wl->cullradius))
+                       continue;
+
                // mark the leafs we care about so only things in those leafs will matter
                for (i = 0;i < wl->numleafs;i++)
                        wl->leafs[i]->worldnodeframe = shadowframecount;
                // mark the leafs we care about so only things in those leafs will matter
                for (i = 0;i < wl->numleafs;i++)
                        wl->leafs[i]->worldnodeframe = shadowframecount;
@@ -1046,6 +1056,9 @@ void R_ShadowVolumeLighting (int visiblevolumes)
                clipmaxs[1] = rd->origin[1] + cullradius;
                clipmaxs[2] = rd->origin[2] + cullradius;
 
                clipmaxs[1] = rd->origin[1] + cullradius;
                clipmaxs[2] = rd->origin[2] + cullradius;
 
+               if (R_Shadow_ScissorForBBoxAndSphere(clipmins, clipmaxs, rd->origin, rd->cullradius))
+                       continue;
+
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
                R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
                if (!visiblevolumes)
                        R_Shadow_Stage_ShadowVolumes();
                R_TestAndDrawShadowVolume(&cl_entities[0].render, rd->origin, cullradius, lightradius, clipmins, clipmaxs);
@@ -1102,6 +1115,7 @@ void R_ShadowVolumeLighting (int visiblevolumes)
 
        if (!visiblevolumes)
                R_Shadow_Stage_End();
 
        if (!visiblevolumes)
                R_Shadow_Stage_End();
+       qglDisable(GL_SCISSOR_TEST);
 }
 
 static void R_SetFrustum (void)
 }
 
 static void R_SetFrustum (void)
index f68e815..ef65f0d 100644 (file)
--- a/glquake.h
+++ b/glquake.h
@@ -337,6 +337,12 @@ extern int gl_dot3ext;
 #endif
 */
 
 #endif
 */
 
+#ifndef GL_SCISSOR_TEST
+#define GL_SCISSOR_TEST                                0x0C11
+#define GL_SCISSOR_BOX                         0x0C10
+#endif
+
+extern void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
 
 extern void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
 
 
 extern void (GLAPIENTRY *qglClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
 
index 4ee1b62..aa66470 100644 (file)
@@ -37,6 +37,7 @@ cvar_t r_shadow_erasebydrawing = {0, "r_shadow_erasebydrawing", "0"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "0"};
 cvar_t r_shadow_gloss = {0, "r_shadow_gloss", "1"};
 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1"};
+cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1"};
 
 void R_Shadow_ClearWorldLights(void);
 void r_shadow_start(void)
 
 void R_Shadow_ClearWorldLights(void);
 void r_shadow_start(void)
@@ -92,6 +93,7 @@ void R_Shadow_Init(void)
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_erasebydrawing);
        Cvar_RegisterVariable(&r_shadow_gloss);
        Cvar_RegisterVariable(&r_shadow_debuglight);
        Cvar_RegisterVariable(&r_shadow_erasebydrawing);
+       Cvar_RegisterVariable(&r_shadow_scissor);
        R_Shadow_EditLights_Init();
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
 }
        R_Shadow_EditLights_Init();
        R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
 }
@@ -532,6 +534,8 @@ void R_Shadow_Stage_ShadowVolumes(void)
        qglEnable(GL_CULL_FACE);
        qglEnable(GL_DEPTH_TEST);
        r_shadowstage = SHADOWSTAGE_STENCIL;
        qglEnable(GL_CULL_FACE);
        qglEnable(GL_DEPTH_TEST);
        r_shadowstage = SHADOWSTAGE_STENCIL;
+       if (!r_shadow_erasebydrawing.integer)
+               qglClear(GL_STENCIL_BUFFER_BIT);
 }
 
 void R_Shadow_Stage_Light(void)
 }
 
 void R_Shadow_Stage_Light(void)
@@ -578,10 +582,7 @@ int R_Shadow_Stage_EraseShadowVolumes(void)
                return true;
        }
        else
                return true;
        }
        else
-       {
-               qglClear(GL_STENCIL_BUFFER_BIT);
                return false;
                return false;
-       }
 }
 
 void R_Shadow_Stage_End(void)
 }
 
 void R_Shadow_Stage_End(void)
@@ -594,6 +595,7 @@ void R_Shadow_Stage_End(void)
        // now restore the rest of the state to normal
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
        // now restore the rest of the state to normal
        GL_Color(1, 1, 1, 1);
        qglColorMask(1, 1, 1, 1);
+       qglDisable(GL_SCISSOR_TEST);
        qglDepthFunc(GL_LEQUAL);
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        qglDepthFunc(GL_LEQUAL);
        qglDisable(GL_STENCIL_TEST);
        qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
@@ -611,6 +613,142 @@ void R_Shadow_Stage_End(void)
        r_shadowstage = SHADOWSTAGE_NONE;
 }
 
        r_shadowstage = SHADOWSTAGE_NONE;
 }
 
+int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius)
+{
+       int i, ix1, iy1, ix2, iy2;
+       float x1, y1, x2, y2, x, y;
+       vec3_t smins, smaxs;
+       vec4_t v, v2;
+       if (!r_shadow_scissor.integer)
+               return false;
+       // if view is inside the box, just say yes it's visible
+       if (r_origin[0] >= mins[0] && r_origin[0] <= maxs[0]
+        && r_origin[1] >= mins[1] && r_origin[1] <= maxs[1]
+        && r_origin[2] >= mins[2] && r_origin[2] <= maxs[2])
+       {
+               qglDisable(GL_SCISSOR_TEST);
+               return false;
+       }
+       VectorSubtract(r_origin, origin, v);
+       if (DotProduct(v, v) < radius * radius)
+       {
+               qglDisable(GL_SCISSOR_TEST);
+               return false;
+       }
+       // create viewspace bbox
+       for (i = 0;i < 8;i++)
+       {
+               v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_origin[0];
+               v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_origin[1];
+               v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_origin[2];
+               v2[0] = DotProduct(v, vright);
+               v2[1] = DotProduct(v, vup);
+               v2[2] = DotProduct(v, vpn);
+               if (i)
+               {
+                       if (smins[0] > v2[0]) smins[0] = v2[0];
+                       if (smaxs[0] < v2[0]) smaxs[0] = v2[0];
+                       if (smins[1] > v2[1]) smins[1] = v2[1];
+                       if (smaxs[1] < v2[1]) smaxs[1] = v2[1];
+                       if (smins[2] > v2[2]) smins[2] = v2[2];
+                       if (smaxs[2] < v2[2]) smaxs[2] = v2[2];
+               }
+               else
+               {
+                       smins[0] = smaxs[0] = v2[0];
+                       smins[1] = smaxs[1] = v2[1];
+                       smins[2] = smaxs[2] = v2[2];
+               }
+       }
+       // now we have a bbox in viewspace
+       // clip it to the viewspace version of the sphere
+       v[0] = origin[0] - r_origin[0];
+       v[1] = origin[1] - r_origin[1];
+       v[2] = origin[2] - r_origin[2];
+       v2[0] = DotProduct(v, vright);
+       v2[1] = DotProduct(v, vup);
+       v2[2] = DotProduct(v, vpn);
+       if (smins[0] < v2[0] - radius) smins[0] = v2[0] - radius;
+       if (smaxs[0] < v2[0] - radius) smaxs[0] = v2[0] + radius;
+       if (smins[1] < v2[1] - radius) smins[1] = v2[1] - radius;
+       if (smaxs[1] < v2[1] - radius) smaxs[1] = v2[1] + radius;
+       if (smins[2] < v2[2] - radius) smins[2] = v2[2] - radius;
+       if (smaxs[2] < v2[2] - radius) smaxs[2] = v2[2] + radius;
+       // clip it to the view plane
+       if (smins[2] < 1)
+               smins[2] = 1;
+       // return true if that culled the box
+       if (smins[2] >= smaxs[2])
+               return true;
+       // ok some of it is infront of the view, transform each corner back to
+       // worldspace and then to screenspace and make screen rect
+       for (i = 0;i < 8;i++)
+       {
+               v2[0] = (i & 1) ? smins[0] : smaxs[0];
+               v2[1] = (i & 2) ? smins[1] : smaxs[1];
+               v2[2] = (i & 4) ? smins[2] : smaxs[2];
+               v[0] = v2[0] * vright[0] + v2[1] * vup[0] + v2[2] * vpn[0] + r_origin[0];
+               v[1] = v2[0] * vright[1] + v2[1] * vup[1] + v2[2] * vpn[1] + r_origin[1];
+               v[2] = v2[0] * vright[2] + v2[1] * vup[2] + v2[2] * vpn[2] + r_origin[2];
+               v[3] = 1.0f;
+               GL_TransformToScreen(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]);
+               x = v2[0];
+               y = v2[1];
+               if (i)
+               {
+                       if (x1 > x) x1 = x;
+                       if (x2 < x) x2 = x;
+                       if (y1 > y) y1 = y;
+                       if (y2 < y) y2 = y;
+               }
+               else
+               {
+                       x1 = x2 = x;
+                       y1 = y2 = y;
+               }
+       }
+       /*
+       // this code doesn't handle boxes with any points behind view properly
+       x1 = 1000;x2 = -1000;
+       y1 = 1000;y2 = -1000;
+       for (i = 0;i < 8;i++)
+       {
+               v[0] = (i & 1) ? mins[0] : maxs[0];
+               v[1] = (i & 2) ? mins[1] : maxs[1];
+               v[2] = (i & 4) ? mins[2] : maxs[2];
+               v[3] = 1.0f;
+               GL_TransformToScreen(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 (v2[2] > 0)
+               {
+                       x = v2[0];
+                       y = v2[1];
+
+                       if (x1 > x) x1 = x;
+                       if (x2 < x) x2 = x;
+                       if (y1 > y) y1 = y;
+                       if (y2 < y) y2 = y;
+               }
+       }
+       */
+       ix1 = x1 - 1.0f;
+       iy1 = y1 - 1.0f;
+       ix2 = x2 + 1.0f;
+       iy2 = y2 + 1.0f;
+       //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
+       if (ix1 < r_refdef.x) ix1 = r_refdef.x;
+       if (iy1 < r_refdef.y) iy1 = r_refdef.y;
+       if (ix2 > r_refdef.x + r_refdef.width) ix2 = r_refdef.x + r_refdef.width;
+       if (iy2 > r_refdef.y + r_refdef.height) iy2 = r_refdef.y + r_refdef.height;
+       if (ix2 <= ix1 || iy2 <= iy1)
+               return true;
+       // set up the scissor rectangle
+       qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
+       qglEnable(GL_SCISSOR_TEST);
+       return false;
+}
+
 void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
 {
        int i;
 void R_Shadow_GenTexCoords_Attenuation2D1D(float *out2d, float *out1d, int numverts, const float *vertex, const float *svectors, const float *tvectors, const float *normals, const vec3_t relativelightorigin, float lightradius)
 {
        int i;
index 1aa8532..9b11935 100644 (file)
@@ -24,6 +24,7 @@ void R_Shadow_Stage_Light(void);
 // otherwise clears stencil
 int R_Shadow_Stage_EraseShadowVolumes(void);
 void R_Shadow_Stage_End(void);
 // otherwise clears stencil
 int R_Shadow_Stage_EraseShadowVolumes(void);
 void R_Shadow_Stage_End(void);
+int R_Shadow_ScissorForBBoxAndSphere(const float *mins, const float *maxs, const float *origin, float radius);
 
 typedef struct worldlight_s
 {
 
 typedef struct worldlight_s
 {
index a65d5a7..88f2dbb 100644 (file)
@@ -179,6 +179,7 @@ void (GLAPIENTRY *qglTexImage3D)(GLenum target, GLint level, GLenum internalForm
 void (GLAPIENTRY *qglTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
 void (GLAPIENTRY *qglCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
 
 void (GLAPIENTRY *qglTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
 void (GLAPIENTRY *qglCopyTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
 
+void (GLAPIENTRY *qglScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
 
 int GL_CheckExtension(const char *name, const gl_extensionfunctionlist_t *funcs, const char *disableparm, int silent)
 {
 
 int GL_CheckExtension(const char *name, const gl_extensionfunctionlist_t *funcs, const char *disableparm, int silent)
 {
@@ -303,6 +304,7 @@ static gl_extensionfunctionlist_t opengl110funcs[] =
        {"glCopyTexImage2D", (void **) &qglCopyTexImage2D},
        {"glCopyTexSubImage1D", (void **) &qglCopyTexSubImage1D},
        {"glCopyTexSubImage2D", (void **) &qglCopyTexSubImage2D},
        {"glCopyTexImage2D", (void **) &qglCopyTexImage2D},
        {"glCopyTexSubImage1D", (void **) &qglCopyTexSubImage1D},
        {"glCopyTexSubImage2D", (void **) &qglCopyTexSubImage2D},
+       {"glScissor", (void **) &qglScissor},
        {NULL, NULL}
 };
 
        {NULL, NULL}
 };