]> de.git.xonotic.org Git - xonotic/darkplaces.git/commitdiff
added rmesh_t and R_Mesh_AddVertex3f, R_Mesh_AddPolygon3f, R_Mesh_AddBrushMeshFromPla...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 8 May 2005 12:59:38 +0000 (12:59 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Sun, 8 May 2005 12:59:38 +0000 (12:59 +0000)
R_Shadow_ScissorForBBox now uses R_Mesh_AddBrushMeshFromPlanes function to get an exact clipped box-brush vertex set for calculating scissor area, this should reduce the scissor area used in some cases compared to the old hacky method
added nearclip plane to frustum[] array (only used by R_Shadow_ScissorForBBox)

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

gl_rmain.c
r_shadow.c
r_shadow.h
render.h

index be9c5aaec45ffaf584cdb573f3b1deaabd3cad66..0527c171ef753124d64fd0a3d5d158211f4c7b09 100644 (file)
@@ -21,11 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include "quakedef.h"
 #include "r_shadow.h"
+#include "polygon.h"
 
 // used for dlight push checking and other things
 int r_framecount;
 
-mplane_t frustum[4];
+mplane_t frustum[5];
 
 matrix4x4_t r_identitymatrix;
 
@@ -770,6 +771,11 @@ static void R_SetFrustum(void)
        RotatePointAroundVector( frustum[3].normal, r_viewleft, r_viewforward, (90 - r_view_fov_y / 2));
        frustum[3].dist = DotProduct (r_vieworigin, frustum[3].normal);
        PlaneClassify(&frustum[3]);
+
+       // nearclip plane
+       VectorCopy(r_viewforward, frustum[4].normal);
+       frustum[4].dist = DotProduct (r_vieworigin, frustum[4].normal) + 1.0f;
+       PlaneClassify(&frustum[4]);
 }
 
 static void R_BlendView(void)
@@ -1362,3 +1368,71 @@ void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, int depth
        R_Mesh_Draw(0, 4, 2, polygonelements);
 }
 
+int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v)
+{
+       int i;
+       float *vertex3f;
+       for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
+               if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
+                       break;
+       if (i == mesh->numvertices)
+       {
+               if (mesh->numvertices < mesh->maxvertices)
+               {
+                       VectorCopy(v, vertex3f);
+                       mesh->numvertices++;
+               }
+               return mesh->numvertices;
+       }
+       else
+               return i;
+}
+
+void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
+{
+       int i;
+       int *e, element[3];
+       element[0] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
+       element[1] = R_Mesh_AddVertex3f(mesh, vertex3f);vertex3f += 3;
+       e = mesh->element3i + mesh->numtriangles * 3;
+       for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
+       {
+               element[2] = R_Mesh_AddVertex3f(mesh, vertex3f);
+               if (mesh->numtriangles < mesh->maxtriangles)
+               {
+                       *e++ = element[0];
+                       *e++ = element[1];
+                       *e++ = element[2];
+                       mesh->numtriangles++;
+               }
+               element[1] = element[2];
+       }
+}
+
+void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
+{
+       int planenum, planenum2;
+       int w;
+       int tempnumpoints;
+       mplane_t *plane, *plane2;
+       float temppoints[2][256*3];
+       for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
+       {
+               w = 0;
+               tempnumpoints = 4;
+               PolygonF_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->normal[3], 1024.0*1024.0*1024.0);
+               for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
+               {
+                       if (planenum2 == planenum)
+                               continue;
+                       PolygonF_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, 1.0/32.0, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints);
+                       w = !w;
+               }
+               if (tempnumpoints < 3)
+                       continue;
+               // generate elements forming a triangle fan for this polygon
+               R_Mesh_AddPolygon3f(mesh, tempnumpoints, temppoints[w]);
+       }
+}
+
+
index 2779a310075d149acf878ba885af6cf4e8c72259..ca621cca86598221d83ed6ee520361a0a98037cd 100644 (file)
@@ -1262,170 +1262,89 @@ void R_Shadow_Stage_End(void)
        r_shadowstage = R_SHADOWSTAGE_NONE;
 }
 
-int R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
+qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
 {
        int i, ix1, iy1, ix2, iy2;
-       float x1, y1, x2, y2, x, y, f;
-       vec3_t smins, smaxs;
+       float x1, y1, x2, y2;
        vec4_t v, v2;
-       if (!r_shadow_scissor.integer)
-               return false;
-       // if view is inside the box, just say yes it's visible
+       rmesh_t mesh;
+       mplane_t planes[11];
+       float vertex3f[256*3];
+
+       // if view is inside the light box, just say yes it's visible
        if (BoxesOverlap(r_vieworigin, r_vieworigin, mins, maxs))
        {
                GL_Scissor(r_view_x, r_view_y, r_view_width, r_view_height);
                return false;
        }
-       for (i = 0;i < 3;i++)
+
+       // create a temporary brush describing the area the light can affect in worldspace
+       VectorNegate(frustum[0].normal, planes[ 0].normal);planes[ 0].dist = -frustum[0].dist;
+       VectorNegate(frustum[1].normal, planes[ 1].normal);planes[ 1].dist = -frustum[1].dist;
+       VectorNegate(frustum[2].normal, planes[ 2].normal);planes[ 2].dist = -frustum[2].dist;
+       VectorNegate(frustum[3].normal, planes[ 3].normal);planes[ 3].dist = -frustum[3].dist;
+       VectorNegate(frustum[4].normal, planes[ 4].normal);planes[ 4].dist = -frustum[4].dist;
+       VectorSet   (planes[ 5].normal,  1, 0, 0);         planes[ 5].dist =  maxs[0];
+       VectorSet   (planes[ 6].normal, -1, 0, 0);         planes[ 6].dist = -mins[0];
+       VectorSet   (planes[ 7].normal, 0,  1, 0);         planes[ 7].dist =  maxs[1];
+       VectorSet   (planes[ 8].normal, 0, -1, 0);         planes[ 8].dist = -mins[1];
+       VectorSet   (planes[ 9].normal, 0, 0,  1);         planes[ 9].dist =  maxs[2];
+       VectorSet   (planes[10].normal, 0, 0, -1);         planes[10].dist = -mins[2];
+
+       // turn the brush into a mesh
+       memset(&mesh, 0, sizeof(rmesh_t));
+       mesh.maxvertices = 256;
+       mesh.vertex3f = vertex3f;
+       mesh.epsilon2 = (1.0f / (32.0f * 32.0f));
+       R_Mesh_AddBrushMeshFromPlanes(&mesh, 11, planes);
+
+       // if that mesh is empty, the light is not visible at all
+       if (!mesh.numvertices)
+               return true;
+
+       if (!r_shadow_scissor.integer)
+               return false;
+
+       // if that mesh is not empty, check what area of the screen it covers
+       x1 = y1 = x2 = y2 = 0;
+       v[3] = 1.0f;
+       for (i = 0;i < mesh.numvertices;i++)
        {
-               if (r_viewforward[i] >= 0)
+               VectorCopy(mesh.vertex3f + i * 3, v);
+               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 (i)
                {
-                       v[i] = mins[i];
-                       v2[i] = maxs[i];
+                       if (x1 > v2[0]) x1 = v2[0];
+                       if (x2 < v2[0]) x2 = v2[0];
+                       if (y1 > v2[1]) y1 = v2[1];
+                       if (y2 < v2[1]) y2 = v2[1];
                }
                else
                {
-                       v[i] = maxs[i];
-                       v2[i] = mins[i];
+                       x1 = x2 = v2[0];
+                       y1 = y2 = v2[1];
                }
        }
-       f = DotProduct(r_viewforward, r_vieworigin) + 1;
-       if (DotProduct(r_viewforward, v2) <= f)
-       {
-               // entirely behind nearclip plane
-               return true;
-       }
-       if (DotProduct(r_viewforward, v) >= f)
-       {
-               // entirely infront of nearclip plane
-               x1 = y1 = x2 = y2 = 0;
-               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]);
-                       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;
-                       }
-               }
-       }
-       else
-       {
-               // clipped by nearclip plane
-               // this is nasty and crude...
-               // create viewspace bbox
-               for (i = 0;i < 8;i++)
-               {
-                       v[0] = ((i & 1) ? mins[0] : maxs[0]) - r_vieworigin[0];
-                       v[1] = ((i & 2) ? mins[1] : maxs[1]) - r_vieworigin[1];
-                       v[2] = ((i & 4) ? mins[2] : maxs[2]) - r_vieworigin[2];
-                       v2[0] = -DotProduct(v, r_viewleft);
-                       v2[1] = DotProduct(v, r_viewup);
-                       v2[2] = DotProduct(v, r_viewforward);
-                       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 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
-               // initialize these variables just to avoid compiler warnings
-               x1 = y1 = x2 = y2 = 0;
-               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] * -r_viewleft[0] + v2[1] * r_viewup[0] + v2[2] * r_viewforward[0] + r_vieworigin[0];
-                       v[1] = v2[0] * -r_viewleft[1] + v2[1] * r_viewup[1] + v2[2] * r_viewforward[1] + r_vieworigin[1];
-                       v[2] = v2[0] * -r_viewleft[2] + v2[1] * r_viewup[2] + v2[2] * r_viewforward[2] + r_vieworigin[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;
-                       }
-               }
-               */
-       }
+       // now convert the scissor rectangle to integer screen coordinates
        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);
+
+       // clamp it to the screen
        if (ix1 < r_view_x) ix1 = r_view_x;
        if (iy1 < r_view_y) iy1 = r_view_y;
        if (ix2 > r_view_x + r_view_width) ix2 = r_view_x + r_view_width;
        if (iy2 > r_view_y + r_view_height) iy2 = r_view_y + r_view_height;
+
+       // if it is inside out, it's not visible
        if (ix2 <= ix1 || iy2 <= iy1)
                return true;
-       // set up the scissor rectangle
+
+       // the light area is visible, set up the scissor rectangle
        GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1);
        //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1);
        //qglEnable(GL_SCISSOR_TEST);
index b3679465ae18abc8bac82abdba4c39d7c87d512c..b63a52564ee43c8f22bb2be193f0263ce042383c 100644 (file)
@@ -40,7 +40,7 @@ void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *inv
 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int numtriangles, const int *elements, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, const float *lightcolorbase, const float *lightcolorpants, const float *lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *bumptexture, rtexture_t *glosstexture);
 
 void R_Shadow_RenderVolume(int numvertices, int numtriangles, const float *vertex3f, const int *element3i);
-int R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
+qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs);
 
 // these never change, they are used to create attenuation matrices
 extern matrix4x4_t matrix_attenuationxyz;
index 1a46caad5d92c47a15c853c81f28890edcf3e346..98ea4ebf7d84ef69bc3bb6bdf58d02d5048dfaa5 100644 (file)
--- a/render.h
+++ b/render.h
@@ -78,9 +78,34 @@ extern cvar_t r_watershader;
 
 extern cvar_t developer_texturelogging;
 
+typedef struct rmesh_s
+{
+       // vertices of this mesh
+       int maxvertices;
+       int numvertices;
+       float *vertex3f;
+       float *svector3f;
+       float *tvector3f;
+       float *normal3f;
+       float *texcoord2f;
+       float *texcoordlightmap2f;
+       float *color4f;
+       // triangles of this mesh
+       int maxtriangles;
+       int numtriangles;
+       int *element3i;
+       int *neighbor3i;
+       // snapping epsilon
+       float epsilon2;
+}
+rmesh_t;
+
 // useful functions for rendering
 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b);
 void R_FillColors(float *out, int verts, float r, float g, float b, float a);
+int R_Mesh_AddVertex3f(rmesh_t *mesh, const float *v);
+void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f);
+void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes);
 
 #define        TOP_RANGE               16                      // soldier uniform colors
 #define        BOTTOM_RANGE    96
@@ -88,7 +113,7 @@ void R_FillColors(float *out, int verts, float r, float g, float b, float a);
 //=============================================================================
 
 extern int r_framecount;
-extern mplane_t frustum[4];
+extern mplane_t frustum[5];
 
 extern int c_alias_polys, c_light_polys, c_faces, c_nodes, c_leafs, c_models, c_bmodels, c_sprites, c_particles, c_dlights, c_meshs, c_meshelements, c_rt_lights, c_rt_clears, c_rt_scissored, c_rt_shadowmeshes, c_rt_shadowtris, c_rt_lightmeshes, c_rt_lighttris, c_rtcached_shadowmeshes, c_rtcached_shadowtris, c_bloom, c_bloomcopies, c_bloomcopypixels, c_bloomdraws, c_bloomdrawpixels;