From 8bbf1d28e7c0f0195cab09ca0f31398fa3b89191 Mon Sep 17 00:00:00 2001 From: divverent Date: Wed, 13 Oct 2010 16:08:13 +0000 Subject: [PATCH] r_water_scissormode: 0 = none, 1 = glScissor, 2 = glScissor and frustum culling git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@10520 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_backend.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ gl_backend.h | 1 + gl_rmain.c | 133 +++++++++++++++++++++++++++++++++++++------ r_shadow.c | 157 +++++---------------------------------------------- render.h | 1 + 5 files changed, 281 insertions(+), 161 deletions(-) diff --git a/gl_backend.c b/gl_backend.c index 78e00828..9423cc75 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -524,6 +524,156 @@ void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out[2] = v->z + (out[2] * iw + 1.0f) * v->depth * 0.5f; } +static int bboxedges[12][2] = +{ + // top + {0, 1}, // +X + {0, 2}, // +Y + {1, 3}, // Y, +X + {2, 3}, // X, +Y + // bottom + {4, 5}, // +X + {4, 6}, // +Y + {5, 7}, // Y, +X + {6, 7}, // X, +Y + // verticals + {0, 4}, // +Z + {1, 5}, // X, +Z + {2, 6}, // Y, +Z + {3, 7}, // XY, +Z +}; + +qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor) +{ + int i, ix1, iy1, ix2, iy2; + float x1, y1, x2, y2; + vec4_t v, v2; + float vertex[20][3]; + int j, k; + vec4_t plane4f; + int numvertices; + float corner[8][4]; + float dist[8]; + int sign[8]; + float f; + + scissor[0] = r_refdef.view.viewport.x; + scissor[1] = r_refdef.view.viewport.y; + scissor[2] = r_refdef.view.viewport.width; + scissor[3] = r_refdef.view.viewport.height; + + // if view is inside the box, just say yes it's visible + if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs)) + return false; + + x1 = y1 = x2 = y2 = 0; + + // transform all corners that are infront of the nearclip plane + VectorNegate(r_refdef.view.frustum[4].normal, plane4f); + plane4f[3] = r_refdef.view.frustum[4].dist; + numvertices = 0; + for (i = 0;i < 8;i++) + { + Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1); + dist[i] = DotProduct4(corner[i], plane4f); + sign[i] = dist[i] > 0; + if (!sign[i]) + { + VectorCopy(corner[i], vertex[numvertices]); + numvertices++; + } + } + // if some points are behind the nearclip, add clipped edge points to make + // sure that the scissor boundary is complete + if (numvertices > 0 && numvertices < 8) + { + // add clipped edge points + for (i = 0;i < 12;i++) + { + j = bboxedges[i][0]; + k = bboxedges[i][1]; + if (sign[j] != sign[k]) + { + f = dist[j] / (dist[j] - dist[k]); + VectorLerp(corner[j], f, corner[k], vertex[numvertices]); + numvertices++; + } + } + } + + // if we have no points to check, it is behind the view plane + if (!numvertices) + return true; + + // if we have some points to transform, check what screen area is covered + x1 = y1 = x2 = y2 = 0; + v[3] = 1.0f; + //Con_Printf("%i vertices to transform...\n", numvertices); + for (i = 0;i < numvertices;i++) + { + VectorCopy(vertex[i], v); + 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) + { + 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 + { + x1 = x2 = v2[0]; + y1 = y2 = v2[1]; + } + } + + // now convert the scissor rectangle to integer screen coordinates + ix1 = (int)(x1 - 1.0f); + //iy1 = vid.height - (int)(y2 - 1.0f); + //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f); + iy1 = (int)(y1 - 1.0f); + ix2 = (int)(x2 + 1.0f); + //iy2 = vid.height - (int)(y1 + 1.0f); + //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f); + iy2 = (int)(y2 + 1.0f); + //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); + + // clamp it to the screen + if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x; + if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y; + if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width; + if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height; + + // if it is inside out, it's not visible + if (ix2 <= ix1 || iy2 <= iy1) + return true; + + // the light area is visible, set up the scissor rectangle + scissor[0] = ix1; + scissor[1] = iy1; + scissor[2] = ix2 - ix1; + scissor[3] = iy2 - iy1; + + // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one + switch(vid.renderpath) + { + case RENDERPATH_D3D9: + case RENDERPATH_D3D10: + case RENDERPATH_D3D11: + scissor[1] = vid.height - scissor[1] - scissor[3]; + break; + case RENDERPATH_GL11: + case RENDERPATH_GL13: + case RENDERPATH_GL20: + case RENDERPATH_CGGL: + break; + } + + return false; +} + + static void R_Viewport_ApplyNearClipPlaneFloatGL(const r_viewport_t *v, float *m, float normalx, float normaly, float normalz, float dist) { float q[4]; diff --git a/gl_backend.h b/gl_backend.h index aff9f402..596b4bf0 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -20,6 +20,7 @@ extern int quadelement3i[QUADELEMENTS_MAXQUADS*6]; extern unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6]; void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out); +qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor); void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float zNear, float zFar, const float *nearplane); void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, float zFar, const float *nearplane); void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane); diff --git a/gl_rmain.c b/gl_rmain.c index 8d60afd8..7b251da3 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -154,6 +154,7 @@ cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"}; cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"}; cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"}; +cvar_t r_water_scissormode = {CVAR_SAVE, "r_water_scissormode", "2", "scissor (1) and cull (2) water renders"}; cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"}; cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"}; @@ -7285,6 +7286,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_water_clippingplanebias); Cvar_RegisterVariable(&r_water_refractdistort); Cvar_RegisterVariable(&r_water_reflectdistort); + Cvar_RegisterVariable(&r_water_scissormode); Cvar_RegisterVariable(&r_lerpsprites); Cvar_RegisterVariable(&r_lerpmodels); Cvar_RegisterVariable(&r_lerplightstyles); @@ -8006,12 +8008,28 @@ static void R_DrawModelsAddWaterPlanes(void) } } -static void R_View_SetFrustum(void) +static void R_View_SetFrustum(const int *scissor) { int i; - double slopex, slopey; + double fpx, fnx, fpy, fny; vec3_t forward, left, up, origin; + if(scissor) + { + // flipped x coordinates (because x points left here) + fpx = 1.0 - 2.0 * (scissor[0] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width); + fnx = 1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width); + + // non-flipped y coordinates + fny = -1.0 + 2.0 * (scissor[1] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height); + } + else + { + fnx = fny = -1; + fpx = fpy = +1; + } + // we can't trust r_refdef.view.forward and friends in reflected scenes Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin); @@ -8079,13 +8097,17 @@ static void R_View_SetFrustum(void) if (r_refdef.view.useperspective) { - slopex = 1.0 / r_refdef.view.frustum_x; - slopey = 1.0 / r_refdef.view.frustum_y; - VectorMA(forward, -slopex, left, r_refdef.view.frustum[0].normal); - VectorMA(forward, slopex, left, r_refdef.view.frustum[1].normal); - VectorMA(forward, -slopey, up , r_refdef.view.frustum[2].normal); - VectorMA(forward, slopey, up , r_refdef.view.frustum[3].normal); - VectorCopy(forward, r_refdef.view.frustum[4].normal); + // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling + VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]); + VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]); + VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]); + VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]); + + // then the normals from the corners relative to origin + CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal); + CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal); + CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal); + CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal); // Leaving those out was a mistake, those were in the old code, and they // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix @@ -8095,11 +8117,14 @@ static void R_View_SetFrustum(void) VectorNormalize(r_refdef.view.frustum[2].normal); VectorNormalize(r_refdef.view.frustum[3].normal); - // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling - VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]); - VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]); - VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]); - VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]); + // make the corners absolute + VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]); + VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]); + VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]); + VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]); + + // one more normal + VectorCopy(forward, r_refdef.view.frustum[4].normal); r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal); r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal); @@ -8161,10 +8186,19 @@ static void R_View_SetFrustum(void) //PlaneClassify(&frustum[4]); } +void R_View_UpdateWithScissor(const int *myscissor) +{ + R_Main_ResizeViewCache(); + R_View_SetFrustum(myscissor); + R_View_WorldVisibility(r_refdef.view.useclipplane); + R_View_UpdateEntityVisible(); + R_View_UpdateEntityLighting(); +} + void R_View_Update(void) { R_Main_ResizeViewCache(); - R_View_SetFrustum(); + R_View_SetFrustum(NULL); R_View_WorldVisibility(r_refdef.view.useclipplane); R_View_UpdateEntityVisible(); R_View_UpdateEntityLighting(); @@ -8479,6 +8513,18 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) p->materialflags = 0; p->pvsvalid = false; p->camera_entity = t->camera_entity; + VectorCopy(surface->mins, p->mins); + VectorCopy(surface->maxs, p->maxs); + } + else + { + // merge mins/maxs + p->mins[0] = min(p->mins[0], surface->mins[0]); + p->mins[1] = min(p->mins[1], surface->mins[1]); + p->mins[2] = min(p->mins[2], surface->mins[2]); + p->maxs[0] = min(p->maxs[0], surface->maxs[0]); + p->maxs[1] = min(p->maxs[1], surface->maxs[1]); + p->maxs[2] = min(p->maxs[2], surface->maxs[2]); } // merge this surface's materialflags into the waterplane p->materialflags |= t->currentmaterialflags; @@ -8497,6 +8543,7 @@ void R_Water_AddWaterPlane(msurface_t *surface, int entno) static void R_Water_ProcessPlanes(void) { + int myscissor[4]; r_refdef_view_t originalview; r_refdef_view_t myview; int planeindex; @@ -8545,11 +8592,19 @@ static void R_Water_ProcessPlanes(void) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)) { r_refdef.view = myview; + if(r_water_scissormode.integer) + { + R_SetupView(true); + if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) + continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible + } + // render reflected scene and copy into texture Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2); // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems) Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin); r_refdef.view.clipplane = p->plane; + // reverse the cullface settings for this render r_refdef.view.cullface_front = GL_FRONT; r_refdef.view.cullface_back = GL_BACK; @@ -8564,7 +8619,12 @@ static void R_Water_ProcessPlanes(void) R_ResetViewRendering3D(); R_ClearScreen(r_refdef.fogenabled); - R_View_Update(); + if(r_water_scissormode.integer >= 2) + R_View_UpdateWithScissor(myscissor); + else + R_View_Update(); + if(r_water_scissormode.integer) + GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); R_RenderScene(); R_Mesh_CopyToTexture(p->texture_reflection, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); @@ -8574,8 +8634,15 @@ static void R_Water_ProcessPlanes(void) // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted) if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION)) { - r_waterstate.renderingrefraction = true; r_refdef.view = myview; + if(r_water_scissormode.integer) + { + R_SetupView(true); + if(R_ScissorForBBox(p->mins, p->maxs, myscissor)) + continue; // FIXME the plane then still may get rendered but with broken texture, but it sure won't be visible + } + + r_waterstate.renderingrefraction = true; r_refdef.view.clipplane = p->plane; VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal); @@ -8598,7 +8665,12 @@ static void R_Water_ProcessPlanes(void) R_ResetViewRendering3D(); R_ClearScreen(r_refdef.fogenabled); - R_View_Update(); + if(r_water_scissormode.integer >= 2) + R_View_UpdateWithScissor(myscissor); + else + R_View_Update(); + if(r_water_scissormode.integer) + GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]); R_RenderScene(); R_Mesh_CopyToTexture(p->texture_refraction, 0, 0, r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height); @@ -8623,6 +8695,9 @@ static void R_Water_ProcessPlanes(void) CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin); } + // note: all of the view is used for displaying... so + // there is no use in scissoring + // reverse the cullface settings for this render r_refdef.view.cullface_front = GL_FRONT; r_refdef.view.cullface_back = GL_BACK; @@ -9472,6 +9547,7 @@ void R_RenderView(void) GL_Scissor(0, 0, vid.width, vid.height); GL_ScissorTest(false); + CHECKGLERROR } @@ -9723,6 +9799,27 @@ void R_RenderScene(void) R_TimeReport("coronas"); } +#if 0 + { + GL_DepthTest(false); + qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + GL_Color(1, 1, 1, 1); + qglBegin(GL_POLYGON); + qglVertex3f(r_refdef.view.frustumcorner[0][0], r_refdef.view.frustumcorner[0][1], r_refdef.view.frustumcorner[0][2]); + qglVertex3f(r_refdef.view.frustumcorner[1][0], r_refdef.view.frustumcorner[1][1], r_refdef.view.frustumcorner[1][2]); + qglVertex3f(r_refdef.view.frustumcorner[3][0], r_refdef.view.frustumcorner[3][1], r_refdef.view.frustumcorner[3][2]); + qglVertex3f(r_refdef.view.frustumcorner[2][0], r_refdef.view.frustumcorner[2][1], r_refdef.view.frustumcorner[2][2]); + qglEnd(); + qglBegin(GL_POLYGON); + qglVertex3f(r_refdef.view.frustumcorner[0][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[0][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[0][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[1][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[1][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[1][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[3][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[3][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[3][2] + 1000 * r_refdef.view.forward[2]); + qglVertex3f(r_refdef.view.frustumcorner[2][0] + 1000 * r_refdef.view.forward[0], r_refdef.view.frustumcorner[2][1] + 1000 * r_refdef.view.forward[1], r_refdef.view.frustumcorner[2][2] + 1000 * r_refdef.view.forward[2]); + qglEnd(); + qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } +#endif + // don't let sound skip if going slow if (r_refdef.scene.extraupdate) S_ExtraUpdate (); diff --git a/r_shadow.c b/r_shadow.c index bceb2359..fe060e00 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -2265,157 +2265,28 @@ void R_Shadow_RenderMode_End(void) r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE; } -int bboxedges[12][2] = -{ - // top - {0, 1}, // +X - {0, 2}, // +Y - {1, 3}, // Y, +X - {2, 3}, // X, +Y - // bottom - {4, 5}, // +X - {4, 6}, // +Y - {5, 7}, // Y, +X - {6, 7}, // X, +Y - // verticals - {0, 4}, // +Z - {1, 5}, // X, +Z - {2, 6}, // Y, +Z - {3, 7}, // XY, +Z -}; - qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs) { - int i, ix1, iy1, ix2, iy2; - float x1, y1, x2, y2; - vec4_t v, v2; - float vertex[20][3]; - int j, k; - vec4_t plane4f; - int numvertices; - float corner[8][4]; - float dist[8]; - int sign[8]; - float f; - - r_shadow_lightscissor[0] = r_refdef.view.viewport.x; - r_shadow_lightscissor[1] = r_refdef.view.viewport.y; - r_shadow_lightscissor[2] = r_refdef.view.viewport.width; - r_shadow_lightscissor[3] = r_refdef.view.viewport.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)) - return false; - - x1 = y1 = x2 = y2 = 0; - - // transform all corners that are infront of the nearclip plane - VectorNegate(r_refdef.view.frustum[4].normal, plane4f); - plane4f[3] = r_refdef.view.frustum[4].dist; - numvertices = 0; - for (i = 0;i < 8;i++) - { - Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1); - dist[i] = DotProduct4(corner[i], plane4f); - sign[i] = dist[i] > 0; - if (!sign[i]) - { - VectorCopy(corner[i], vertex[numvertices]); - numvertices++; - } - } - // if some points are behind the nearclip, add clipped edge points to make - // sure that the scissor boundary is complete - if (numvertices > 0 && numvertices < 8) { - // add clipped edge points - for (i = 0;i < 12;i++) - { - j = bboxedges[i][0]; - k = bboxedges[i][1]; - if (sign[j] != sign[k]) - { - f = dist[j] / (dist[j] - dist[k]); - VectorLerp(corner[j], f, corner[k], vertex[numvertices]); - numvertices++; - } - } - } - - // if we have no points to check, the light is behind the view plane - if (!numvertices) - return true; - - // if we have some points to transform, check what screen area is covered - x1 = y1 = x2 = y2 = 0; - v[3] = 1.0f; - //Con_Printf("%i vertices to transform...\n", numvertices); - for (i = 0;i < numvertices;i++) - { - VectorCopy(vertex[i], v); - 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) - { - 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 - { - x1 = x2 = v2[0]; - y1 = y2 = v2[1]; - } + r_shadow_lightscissor[0] = r_refdef.view.viewport.x; + r_shadow_lightscissor[1] = r_refdef.view.viewport.y; + r_shadow_lightscissor[2] = r_refdef.view.viewport.width; + r_shadow_lightscissor[3] = r_refdef.view.viewport.height; + return false; } - // now convert the scissor rectangle to integer screen coordinates - ix1 = (int)(x1 - 1.0f); - //iy1 = vid.height - (int)(y2 - 1.0f); - //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f); - iy1 = (int)(y1 - 1.0f); - ix2 = (int)(x2 + 1.0f); - //iy2 = vid.height - (int)(y1 + 1.0f); - //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f); - iy2 = (int)(y2 + 1.0f); - //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2); - - // clamp it to the screen - if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x; - if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y; - if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width; - if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height; - - // if it is inside out, it's not visible - if (ix2 <= ix1 || iy2 <= iy1) - return true; - - // the light area is visible, set up the scissor rectangle - r_shadow_lightscissor[0] = ix1; - r_shadow_lightscissor[1] = iy1; - r_shadow_lightscissor[2] = ix2 - ix1; - r_shadow_lightscissor[3] = iy2 - iy1; - - // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one - switch(vid.renderpath) + if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor)) { - case RENDERPATH_D3D9: - case RENDERPATH_D3D10: - case RENDERPATH_D3D11: - r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3]; - break; - case RENDERPATH_GL11: - case RENDERPATH_GL13: - case RENDERPATH_GL20: - case RENDERPATH_CGGL: - break; + if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x + || r_shadow_lightscissor[1] != r_refdef.view.viewport.y + || r_shadow_lightscissor[2] != r_refdef.view.viewport.width + || r_shadow_lightscissor[3] != r_refdef.view.viewport.height) + r_refdef.stats.lights_scissored++; + return false; } - - r_refdef.stats.lights_scissored++; - return false; + else + return true; // invisible } static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor) diff --git a/render.h b/render.h index 7a5f8466..6115f5bc 100644 --- a/render.h +++ b/render.h @@ -531,6 +531,7 @@ typedef struct r_waterstate_waterplane_s unsigned char pvsbits[(MAX_MAP_LEAFS+7)>>3]; // FIXME: buffer overflow on huge maps qboolean pvsvalid; int camera_entity; + vec3_t mins, maxs; } r_waterstate_waterplane_t; -- 2.39.2