From af0dcabc0e2b5e187cc9182015b612d5ae4efb0b Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 8 May 2005 12:59:38 +0000 Subject: [PATCH] added rmesh_t and R_Mesh_AddVertex3f, R_Mesh_AddPolygon3f, R_Mesh_AddBrushMeshFromPlanes functions 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 | 76 ++++++++++++++++++++- r_shadow.c | 193 ++++++++++++++++------------------------------------- r_shadow.h | 2 +- render.h | 27 +++++++- 4 files changed, 158 insertions(+), 140 deletions(-) diff --git a/gl_rmain.c b/gl_rmain.c index be9c5aae..0527c171 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -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]); + } +} + + diff --git a/r_shadow.c b/r_shadow.c index 2779a310..ca621cca 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -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); diff --git a/r_shadow.h b/r_shadow.h index b3679465..b63a5256 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -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; diff --git a/render.h b/render.h index 1a46caad..98ea4ebf 100644 --- 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; -- 2.39.2