X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=gl_rmain.c;h=f6475aa4b72fe6a2b9df52e67dc445e925a02b9e;hb=2b5159a96a154813fe8b63bb982a924a3ccd7d3f;hp=76c5fa86069758bdb19f851836e8e34150499dc9;hpb=73964e80e40edfcb0bcaeba50da33ddf120e62f0;p=xonotic%2Fdarkplaces.git diff --git a/gl_rmain.c b/gl_rmain.c index 76c5fa86..f6475aa4 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -34,7 +34,7 @@ r_view_t r_view; r_viewcache_t r_viewcache; cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" }; -cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "shows surfaces as different colors"}; +cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"}; cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"}; cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"}; cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"}; @@ -86,6 +86,7 @@ cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "re cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"}; cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"}; cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"}; +cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"}; cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"}; @@ -119,13 +120,15 @@ static struct r_bloomstate_s r_glsl_bloomshader_t *shader; // arrays for rendering the screen passes - float vertex3f[12]; float screentexcoord2f[8]; float bloomtexcoord2f[8]; float offsettexcoord2f[8]; } r_bloomstate; +// shadow volume bsp struct with automatically growing nodes buffer +svbsp_t r_svbsp; + rtexture_t *r_texture_blanknormalmap; rtexture_t *r_texture_white; rtexture_t *r_texture_black; @@ -143,6 +146,15 @@ r_glsl_permutation_t *r_glsl_permutation; // temporary variable used by a macro int fogtableindex; +// vertex coordinates for a quad that covers the screen exactly +const static float r_screenvertex3f[12] = +{ + 0, 0, 0, + 1, 0, 0, + 1, 1, 0, + 0, 1, 0 +}; + extern void R_DrawModelShadows(void); void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b) @@ -696,22 +708,28 @@ const char *permutationinfo[][2] = {NULL, NULL} }; -void R_GLSL_CompilePermutation(int permutation) +void R_GLSL_CompilePermutation(const char *filename, int permutation) { int i; - r_glsl_permutation_t *p = r_glsl_permutations + permutation; + qboolean shaderfound; + r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); int vertstrings_count; + int geomstrings_count; int fragstrings_count; char *shaderstring; const char *vertstrings_list[SHADERPERMUTATION_COUNT+1]; + const char *geomstrings_list[SHADERPERMUTATION_COUNT+1]; const char *fragstrings_list[SHADERPERMUTATION_COUNT+1]; char permutationname[256]; if (p->compiled) return; p->compiled = true; + p->program = 0; vertstrings_list[0] = "#define VERTEX_SHADER\n"; + geomstrings_list[0] = "#define GEOMETRY_SHADER\n"; fragstrings_list[0] = "#define FRAGMENT_SHADER\n"; vertstrings_count = 1; + geomstrings_count = 1; fragstrings_count = 1; permutationname[0] = 0; for (i = 0;permutationinfo[i][0];i++) @@ -719,6 +737,7 @@ void R_GLSL_CompilePermutation(int permutation) if (permutation & (1<program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, fragstrings_count, fragstrings_list); + shaderfound = true; + } + // clear any lists that are not needed by this shader + if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER)) + vertstrings_count = 0; + if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER)) + geomstrings_count = 0; + if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER)) + fragstrings_count = 0; + // compile the shader program + if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count) + p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list); if (p->program) { CHECKGLERROR qglUseProgramObjectARB(p->program);CHECKGLERROR + // look up all the uniform variable names we care about, so we don't + // have to look them up every time we set them p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal"); p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color"); p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss"); @@ -774,6 +811,7 @@ void R_GLSL_CompilePermutation(int permutation) p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor"); p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor"); p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir"); + // initialize the samplers to refer to the texture units we use if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0); if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1); if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2); @@ -808,55 +846,116 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) // combination of texture, entity, light source, and fogging, only use the // minimum features necessary to avoid wasting rendering time in the // fragment shader on features that are not being used + const char *shaderfilename = NULL; int permutation = 0; float specularscale = rsurface_texture->specularscale; r_glsl_permutation = NULL; + // TODO: implement geometry-shader based shadow volumes someday if (r_shadow_rtlight) { - permutation |= SHADERPERMUTATION_MODE_LIGHTSOURCE; + // light source + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; specularscale *= r_shadow_rtlight->specularscale; if (r_shadow_rtlight->currentcubemap != r_texture_whitecube) permutation |= SHADERPERMUTATION_CUBEFILTER; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - else + else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) { - if (!(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) + // bright unshaded geometry + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + if (rsurface_texture->currentskinframe->glow) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) { - if (modellighting) - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION; - else if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture) - { - if (r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) - { - if (r_refdef.worldmodel->brushq3.deluxemapping_modelspace) - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE; - else - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; - } - else if (r_glsl_deluxemapping.integer >= 2) // fake mode - permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; - } + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; } + } + else if (modellighting) + { + // directional model lighting + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION; if (rsurface_texture->currentskinframe->glow) permutation |= SHADERPERMUTATION_GLOW; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - if (specularscale > 0) - permutation |= SHADERPERMUTATION_SPECULAR; - if (r_refdef.fogenabled) - permutation |= SHADERPERMUTATION_FOG; - if (rsurface_texture->colormapping) - permutation |= SHADERPERMUTATION_COLORMAPPING; - if (r_glsl_offsetmapping.integer) + else { - permutation |= SHADERPERMUTATION_OFFSETMAPPING; - if (r_glsl_offsetmapping_reliefmapping.integer) - permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + // lightmapped wall + shaderfilename = "glsl/default.glsl"; + permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER; + if (r_glsl_deluxemapping.integer >= 1 && rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping) + { + // deluxemapping (light direction texture) + if (rsurface_lightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace) + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE; + else + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + } + else if (r_glsl_deluxemapping.integer >= 2) + { + // fake deluxemapping (uniform light direction in tangentspace) + permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE; + if (specularscale > 0) + permutation |= SHADERPERMUTATION_SPECULAR; + } + else + { + // ordinary lightmapping + permutation |= 0; + } + if (rsurface_texture->currentskinframe->glow) + permutation |= SHADERPERMUTATION_GLOW; + if (r_refdef.fogenabled) + permutation |= SHADERPERMUTATION_FOG; + if (rsurface_texture->colormapping) + permutation |= SHADERPERMUTATION_COLORMAPPING; + if (r_glsl_offsetmapping.integer) + { + permutation |= SHADERPERMUTATION_OFFSETMAPPING; + if (r_glsl_offsetmapping_reliefmapping.integer) + permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING; + } } - if (!r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) { - if (!r_glsl_permutations[permutation].compiled) - R_GLSL_CompilePermutation(permutation); - if (!r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation); + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) { // remove features until we find a valid permutation int i; @@ -866,16 +965,16 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) if (permutation < i) continue; permutation &= i; - if (!r_glsl_permutations[permutation].compiled) - R_GLSL_CompilePermutation(permutation); - if (r_glsl_permutations[permutation].program) + if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled) + R_GLSL_CompilePermutation(shaderfilename, permutation); + if (r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program) break; if (!i) return 0; // utterly failed } } } - r_glsl_permutation = r_glsl_permutations + permutation; + r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); CHECKGLERROR qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR R_Mesh_TexMatrix(0, &rsurface_texture->currenttexmatrix); @@ -949,9 +1048,9 @@ int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting) void R_SwitchSurfaceShader(int permutation) { - if (r_glsl_permutation != r_glsl_permutations + permutation) + if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK)) { - r_glsl_permutation = r_glsl_permutations + permutation; + r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK); CHECKGLERROR qglUseProgramObjectARB(r_glsl_permutation->program); CHECKGLERROR @@ -971,10 +1070,14 @@ void gl_main_start(void) R_BuildFogTexture(); memset(&r_bloomstate, 0, sizeof(r_bloomstate)); memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations)); + memset(&r_svbsp, 0, sizeof (r_svbsp)); } void gl_main_shutdown(void) { + if (r_svbsp.nodes) + Mem_Free(r_svbsp.nodes); + memset(&r_svbsp, 0, sizeof (r_svbsp)); R_FreeTexturePool(&r_main_texturepool); r_texture_blanknormalmap = NULL; r_texture_white = NULL; @@ -1056,6 +1159,7 @@ void GL_Main_Init(void) Cvar_RegisterVariable(&r_hdr); Cvar_RegisterVariable(&r_hdr_scenebrightness); Cvar_RegisterVariable(&r_hdr_glowintensity); + Cvar_RegisterVariable(&r_hdr_range); Cvar_RegisterVariable(&r_smoothnormals_areaweighting); Cvar_RegisterVariable(&developer_texturelogging); Cvar_RegisterVariable(&gl_lightmaps); @@ -1108,7 +1212,7 @@ void GL_Init (void) VID_CheckExtensions(); // LordHavoc: report supported extensions - Con_DPrintf("\nengine extensions: %s\n", vm_sv_extensions ); + Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions ); // clear to black (loading plaque will be seen over this) CHECKGLERROR @@ -1400,23 +1504,78 @@ void R_View_Update(void) R_View_UpdateEntityVisible(); } -void R_ResetViewRendering(void) +void R_SetupView(const matrix4x4_t *matrix) +{ + if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows) + GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip); + else + GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip); + + GL_SetupView_Orientation_FromEntity(matrix); +} + +void R_ResetViewRendering2D(void) { if (gl_support_fragment_shader) { qglUseProgramObjectARB(0);CHECKGLERROR } + DrawQ_Finish(); + // GL is weird because it's bottom to top, r_view.y is top to bottom qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100); GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + GL_Color(1, 1, 1, 1); GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_AlphaTest(false); GL_ScissorTest(false); GL_DepthMask(false); GL_DepthTest(false); R_Mesh_Matrix(&identitymatrix); R_Mesh_ResetTextureState(); + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces +} + +void R_ResetViewRendering3D(void) +{ + if (gl_support_fragment_shader) + { + qglUseProgramObjectARB(0);CHECKGLERROR + } + + DrawQ_Finish(); + + // GL is weird because it's bottom to top, r_view.y is top to bottom + qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR + R_SetupView(&r_view.matrix); + GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height); + GL_Color(1, 1, 1, 1); + GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1); + GL_BlendFunc(GL_ONE, GL_ZERO); + GL_AlphaTest(false); + GL_ScissorTest(true); + GL_DepthMask(true); + GL_DepthTest(true); + R_Mesh_Matrix(&identitymatrix); + R_Mesh_ResetTextureState(); + qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR + qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + qglDepthFunc(GL_LEQUAL);CHECKGLERROR + qglDisable(GL_STENCIL_TEST);CHECKGLERROR + qglStencilMask(~0);CHECKGLERROR + qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR + qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR + GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces } /* @@ -1480,16 +1639,6 @@ void R_ResetViewRendering(void) "#endif // FRAGMENT_SHADER\n" */ -void R_SetupView(const matrix4x4_t *matrix) -{ - if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows) - GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip); - else - GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip); - - GL_SetupView_Orientation_FromEntity(matrix); -} - void R_RenderScene(void); void R_Bloom_StartFrame(void) @@ -1568,12 +1717,6 @@ void R_Bloom_StartFrame(void) r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL); } - // vertex coordinates for a quad that covers the screen exactly - r_bloomstate.vertex3f[0] = 0;r_bloomstate.vertex3f[1] = 0;r_bloomstate.vertex3f[2] = 0; - r_bloomstate.vertex3f[3] = 1;r_bloomstate.vertex3f[4] = 0;r_bloomstate.vertex3f[5] = 0; - r_bloomstate.vertex3f[6] = 1;r_bloomstate.vertex3f[7] = 1;r_bloomstate.vertex3f[8] = 0; - r_bloomstate.vertex3f[9] = 0;r_bloomstate.vertex3f[10] = 1;r_bloomstate.vertex3f[11] = 0; - // set up a texcoord array for the full resolution screen image // (we have to keep this around to copy back during final render) r_bloomstate.screentexcoord2f[0] = 0; @@ -1601,8 +1744,8 @@ void R_Bloom_CopyScreenTexture(float colorscale) { r_refdef.stats.bloom++; - R_ResetViewRendering(); - R_Mesh_VertexPointer(r_bloomstate.vertex3f); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); R_Mesh_ColorPointer(NULL); R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f); R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen)); @@ -1643,12 +1786,12 @@ void R_Bloom_CopyHDRTexture(void) void R_Bloom_MakeTexture(void) { int x, range, dir; - float xoffset, yoffset, r; + float xoffset, yoffset, r, brighten; r_refdef.stats.bloom++; - R_ResetViewRendering(); - R_Mesh_VertexPointer(r_bloomstate.vertex3f); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); R_Mesh_ColorPointer(NULL); // we have a bloom image in the framebuffer @@ -1674,6 +1817,9 @@ void R_Bloom_MakeTexture(void) } range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320; + brighten = r_bloom_brighten.value; + if (r_hdr.integer) + brighten *= r_hdr_range.value; R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom)); R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f); @@ -1701,8 +1847,8 @@ void R_Bloom_MakeTexture(void) // black at the edges // (probably not realistic but looks good enough) //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1); - //r = (dir ? 1.0f : r_bloom_brighten.value)/(range*2+1); - r = (dir ? 1.0f : r_bloom_brighten.value)/(range*2+1)*(1 - x*x/(float)(range*range)); + //r = (dir ? 1.0f : brighten)/(range*2+1); + r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range)); GL_Color(r, r, r, 1); R_Mesh_Draw(0, 4, 2, polygonelements); r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight; @@ -1756,23 +1902,25 @@ void R_HDR_RenderBloomTexture(void) // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance. // TODO: add exposure compensation features + // TODO: add fp16 framebuffer support r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value; + if (r_hdr.integer) + r_view.colorscale /= r_hdr_range.value; R_RenderScene(); - R_ResetViewRendering(); + R_ResetViewRendering2D(); R_Bloom_CopyHDRTexture(); R_Bloom_MakeTexture(); - R_ResetViewRendering(); - GL_ScissorTest(true); - GL_DepthMask(true); - GL_DepthTest(true); + R_ResetViewRendering3D(); + R_ClearScreen(); if (r_timereport_active) R_TimeReport("clear"); + // restore the view settings r_view.width = oldwidth; r_view.height = oldheight; @@ -1785,8 +1933,8 @@ static void R_BlendView(void) // render high dynamic range bloom effect // the bloom texture was made earlier this render, so we just need to // blend it onto the screen... - R_ResetViewRendering(); - R_Mesh_VertexPointer(r_bloomstate.vertex3f); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); R_Mesh_ColorPointer(NULL); GL_Color(1, 1, 1, 1); GL_BlendFunc(GL_ONE, GL_ONE); @@ -1804,8 +1952,8 @@ static void R_BlendView(void) R_Bloom_MakeTexture(); // put the original screen image back in place and blend the bloom // texture on it - R_ResetViewRendering(); - R_Mesh_VertexPointer(r_bloomstate.vertex3f); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); R_Mesh_ColorPointer(NULL); GL_Color(1, 1, 1, 1); GL_BlendFunc(GL_ONE, GL_ZERO); @@ -1833,8 +1981,8 @@ static void R_BlendView(void) if (r_refdef.viewblend[3] >= (1.0f / 256.0f)) { // apply a color tint to the whole view - R_ResetViewRendering(); - R_Mesh_VertexPointer(r_bloomstate.vertex3f); + R_ResetViewRendering2D(); + R_Mesh_VertexPointer(r_screenvertex3f); R_Mesh_ColorPointer(NULL); GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]); @@ -1862,7 +2010,7 @@ void R_UpdateVariables(void) r_refdef.rtworld = r_shadow_realtime_world.integer; r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil; - r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer; + r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer; r_refdef.rtdlightshadows = r_refdef.rtdlight && (r_refdef.rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil; r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1; if (r_showsurfaces.integer) @@ -1924,6 +2072,8 @@ void R_RenderView(void) if (!r_refdef.entities/* || !r_refdef.worldmodel*/) return; //Host_Error ("R_RenderView: NULL worldmodel"); + R_Shadow_UpdateWorldLightSelection(); + CHECKGLERROR if (r_timereport_active) R_TimeReport("setup"); @@ -1932,10 +2082,8 @@ void R_RenderView(void) if (r_timereport_active) R_TimeReport("visibility"); - R_ResetViewRendering(); - GL_ScissorTest(true); - GL_DepthMask(true); - GL_DepthTest(true); + R_ResetViewRendering3D(); + R_ClearScreen(); if (r_timereport_active) R_TimeReport("clear"); @@ -1959,32 +2107,18 @@ void R_RenderView(void) } extern void R_DrawLightningBeams (void); -extern void VM_AddPolygonsToMeshQueue (void); +extern void VM_CL_AddPolygonsToMeshQueue (void); extern void R_DrawPortals (void); void R_RenderScene(void) { - DrawQ_Finish(); - // don't let sound skip if going slow if (r_refdef.extraupdate) S_ExtraUpdate (); - CHECKGLERROR - if (gl_support_fragment_shader) - { - qglUseProgramObjectARB(0);CHECKGLERROR - } - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR - - R_ResetViewRendering(); - R_SetupView(&r_view.matrix); + R_ResetViewRendering3D(); R_MeshQueue_BeginScene(); - R_Shadow_UpdateWorldLightSelection(); - R_SkyStartFrame(); Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0); @@ -2029,6 +2163,8 @@ void R_RenderScene(void) { R_DrawModelShadows(); + R_ResetViewRendering3D(); + // don't let sound skip if going slow if (r_refdef.extraupdate) S_ExtraUpdate (); @@ -2061,7 +2197,7 @@ void R_RenderScene(void) { qglUseProgramObjectARB(0);CHECKGLERROR } - VM_AddPolygonsToMeshQueue(); + VM_CL_AddPolygonsToMeshQueue(); if (r_drawportals.integer) { @@ -2094,13 +2230,7 @@ void R_RenderScene(void) if (r_refdef.extraupdate) S_ExtraUpdate (); - CHECKGLERROR - if (gl_support_fragment_shader) - { - qglUseProgramObjectARB(0);CHECKGLERROR - } - qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR - qglDisable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR + R_ResetViewRendering2D(); } /* @@ -2197,6 +2327,7 @@ void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight GL_DepthMask(true); } GL_DepthTest(!(ent->effects & EF_NODEPTHTEST)); + GL_CullFace((ent->flags & RENDER_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces R_Mesh_VertexPointer(nomodelvertex3f); if (r_refdef.fogenabled) { @@ -2454,13 +2585,14 @@ static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) { + model_t *model = ent->model; + // FIXME: identify models using a better check than ent->model->brush.shadowmesh //int lightmode = ((ent->effects & EF_FULLBRIGHT) || ent->model->brush.shadowmesh) ? 0 : 2; // switch to an alternate material if this is a q1bsp animated material { texture_t *texture = t; - model_t *model = ent->model; int s = ent->skinnum; if ((unsigned int)s >= (unsigned int)model->numskins) s = 0; @@ -2488,36 +2620,45 @@ void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t) // pick a new currentskinframe if the material is animated if (t->numskinframes >= 2) t->currentskinframe = t->skinframes + ((int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes); + if (t->backgroundnumskinframes >= 2) + t->backgroundcurrentskinframe = t->backgroundskinframes + ((int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes); t->currentmaterialflags = t->basematerialflags; t->currentalpha = ent->alpha; - if (t->basematerialflags & MATERIALFLAG_WATERALPHA) + if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer)) t->currentalpha *= r_wateralpha.value; if (!(ent->flags & RENDER_LIGHT)) t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT; if (ent->effects & EF_ADDITIVE) - t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT; + t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW; else if (t->currentalpha < 1) - t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT; + t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW; + if (ent->flags & RENDER_NOCULLFACE) + t->currentmaterialflags |= MATERIALFLAG_NOSHADOW; if (ent->effects & EF_NODEPTHTEST) - t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST; + t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW; if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0) t->currenttexmatrix = r_waterscrollmatrix; else t->currenttexmatrix = identitymatrix; + if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) + t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND; t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f); t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base; t->glosstexture = r_texture_white; + t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white; + t->backgroundglosstexture = r_texture_white; t->specularpower = r_shadow_glossexponent.value; t->specularscale = 0; if (r_shadow_gloss.integer > 0) { - if (t->currentskinframe->gloss) + if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss)) { if (r_shadow_glossintensity.value > 0) { - t->glosstexture = t->currentskinframe->gloss; + t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black; + t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black; t->specularscale = r_shadow_glossintensity.value; } } @@ -2910,14 +3051,31 @@ void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacel static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist) { + int j; int texturesurfaceindex; - for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + if (r_showsurfaces.integer == 2) { - const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; - int k = (int)(((size_t)surface) / sizeof(msurface_t)); - GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 0.2f); - GL_LockArrays(surface->num_firstvertex, surface->num_vertices); - R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + for (j = 0;j < surface->num_triangles;j++) + { + float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale; + GL_Color(f, f, f, 1); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface_model->surfmesh.data_element3i + 3 * (j + surface->num_firsttriangle))); + } + } + } + else + { + for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++) + { + const msurface_t *surface = texturesurfacelist[texturesurfaceindex]; + int k = (int)(((size_t)surface) / sizeof(msurface_t)); + GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 1); + GL_LockArrays(surface->num_firstvertex, surface->num_vertices); + R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)); + } } } @@ -3083,6 +3241,8 @@ static void RSurf_DrawBatch_Lightmap(int texturenumsurfaces, msurface_t **textur static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist) { + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces if (rsurface_mode != RSURFMODE_SHOWSURFACES) { rsurface_mode = RSURFMODE_SHOWSURFACES; @@ -3115,6 +3275,8 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te // restore entity matrix R_Mesh_Matrix(&rsurface_entity->matrix); } + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces GL_DepthMask(true); // LordHavoc: HalfLife maps have freaky skypolys so don't use // skymasking on them, and Quake3 never did sky masking (unlike @@ -3149,9 +3311,6 @@ static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **te static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist) { - int lightmode; - // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh - lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2; if (rsurface_mode != RSURFMODE_GLSL) { rsurface_mode = RSURFMODE_GLSL; @@ -3161,11 +3320,16 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t } if (rsurface_glsl_texture != rsurface_texture || rsurface_glsl_uselightmap != (rsurface_lightmaptexture != NULL)) { + int lightmode; rsurface_glsl_texture = rsurface_texture; - rsurface_glsl_uselightmap = rsurface_lightmaptexture != NULL; + rsurface_glsl_uselightmap = rsurface_lightmaptexture != NULL && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT); + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2); GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)); GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha); + // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh + lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2; R_SetupSurfaceShader(vec3_origin, lightmode == 2); //permutation_deluxemapping = permutation_lightmapping = R_SetupSurfaceShader(vec3_origin, lightmode == 2, false); //if (r_glsl_deluxemapping.integer) @@ -3173,35 +3337,46 @@ static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **t R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f); R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f); GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0); + RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); + R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f); + R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f); + R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f); + if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) + { + R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) + R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); + R_Mesh_ColorPointer(NULL); + } + else if (rsurface_lightmaptexture) + { + R_Mesh_TexBind(7, R_GetTexture(rsurface_lightmaptexture)); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) + R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture)); + R_Mesh_ColorPointer(NULL); + } + else + { + R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); + if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) + R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); + R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f); + } } + else + RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); if (!r_glsl_permutation) return; - RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist); - R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f); - R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f); - R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f); - if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) - { - R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) - R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); - R_Mesh_ColorPointer(NULL); - } - else if (rsurface_lightmaptexture) + if (rsurface_glsl_uselightmap) { R_Mesh_TexBind(7, R_GetTexture(rsurface_lightmaptexture)); if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture)); - R_Mesh_ColorPointer(NULL); } - else + RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); + if (rsurface_texture->backgroundnumskinframes && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)) { - R_Mesh_TexBind(7, R_GetTexture(r_texture_white)); - if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) - R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap)); - R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f); } - RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist); } static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist) @@ -3215,6 +3390,8 @@ static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **t int layerindex; const texturelayer_t *layer; CHECKGLERROR + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2; if (rsurface_mode != RSURFMODE_MULTIPASS) @@ -3331,6 +3508,8 @@ static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **t int layerindex; const texturelayer_t *layer; CHECKGLERROR + GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); + GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh lightmode = ((rsurface_entity->effects & EF_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2; if (rsurface_mode != RSURFMODE_MULTIPASS) @@ -3447,8 +3626,6 @@ static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **textur r_shadow_rtlight = NULL; r_refdef.stats.entities_surfaces += texturenumsurfaces; CHECKGLERROR - GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST)); - GL_CullFace(((rsurface_texture->textureflags & Q3TEXTUREFLAG_TWOSIDED) || (rsurface_entity->flags & RENDER_NOCULLFACE)) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces if (r_showsurfaces.integer) R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist); else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY) @@ -3533,13 +3710,17 @@ void R_QueueTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfa extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface); void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) { - int i, j, f, flagsmask; + int i, j, k, l, endj, f, flagsmask; int counttriangles = 0; + msurface_t *surface, *endsurface, **surfacechain; texture_t *t; + q3mbrush_t *brush; model_t *model = ent->model; + const int *elements; const int maxsurfacelist = 1024; int numsurfacelist = 0; msurface_t *surfacelist[1024]; + vec3_t v; if (model == NULL) return; @@ -3554,7 +3735,6 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) // update light styles if (!skysurfaces && model->brushq1.light_styleupdatechains) { - msurface_t *surface, **surfacechain; for (i = 0;i < model->brushq1.light_styles;i++) { if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]]) @@ -3576,44 +3756,56 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) numsurfacelist = 0; if (ent == r_refdef.worldentity) { - msurface_t *surface; - for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + j = model->firstmodelsurface; + endj = j + model->nummodelsurfaces; + while (j < endj) { - if (!r_viewcache.world_surfacevisible[j]) - continue; - if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture) + // quickly skip over non-visible surfaces + for (;j < endj && !r_viewcache.world_surfacevisible[j];j++) + ; + // quickly iterate over visible surfaces + for (;j < endj && r_viewcache.world_surfacevisible[j];j++) { - if (numsurfacelist) + // process this surface + surface = model->data_surfaces + j; + // if texture or lightmap has changed, start a new batch + if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture) { - R_QueueTextureSurfaceList(numsurfacelist, surfacelist); - numsurfacelist = 0; + if (numsurfacelist) + { + R_QueueTextureSurfaceList(numsurfacelist, surfacelist); + numsurfacelist = 0; + } + t = surface->texture; + rsurface_lightmaptexture = surface->lightmaptexture; + rsurface_texture = t->currentframe; + f = rsurface_texture->currentmaterialflags & flagsmask; } - t = surface->texture; - rsurface_lightmaptexture = surface->lightmaptexture; - rsurface_texture = t->currentframe; - f = rsurface_texture->currentmaterialflags & flagsmask; - } - if (f && surface->num_triangles) - { - // if lightmap parameters changed, rebuild lightmap texture - if (surface->cached_dlight) - R_BuildLightMap(ent, surface); - // add face to draw list - surfacelist[numsurfacelist++] = surface; - counttriangles += surface->num_triangles; - if (numsurfacelist >= maxsurfacelist) + // if this surface fits the criteria, add it to the list + if (f && surface->num_triangles) { - R_QueueTextureSurfaceList(numsurfacelist, surfacelist); - numsurfacelist = 0; + // if lightmap parameters changed, rebuild lightmap texture + if (surface->cached_dlight) + R_BuildLightMap(ent, surface); + // add face to draw list + surfacelist[numsurfacelist++] = surface; + counttriangles += surface->num_triangles; + if (numsurfacelist >= maxsurfacelist) + { + R_QueueTextureSurfaceList(numsurfacelist, surfacelist); + numsurfacelist = 0; + } } } } } else { - msurface_t *surface; - for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++) + surface = model->data_surfaces + model->firstmodelsurface; + endsurface = surface + model->nummodelsurfaces; + for (;surface < endsurface;surface++) { + // if texture or lightmap has changed, start a new batch if (t != surface->texture || rsurface_lightmaptexture != surface->lightmaptexture) { if (numsurfacelist) @@ -3626,6 +3818,7 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) rsurface_texture = t->currentframe; f = rsurface_texture->currentmaterialflags & flagsmask; } + // if this surface fits the criteria, add it to the list if (f && surface->num_triangles) { // if lightmap parameters changed, rebuild lightmap texture @@ -3649,9 +3842,6 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) if (r_showcollisionbrushes.integer && model->brush.num_brushes && !skysurfaces) { - int i; - const msurface_t *surface; - q3mbrush_t *brush; CHECKGLERROR R_Mesh_Matrix(&ent->matrix); R_Mesh_ColorPointer(NULL); @@ -3671,17 +3861,9 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) if (r_showtris.integer || r_shownormals.integer) { - int k, l; - msurface_t *surface; - const int *elements; - vec3_t v; CHECKGLERROR - GL_DepthTest(true); + GL_DepthTest(!r_showdisabledepthtest.integer); GL_DepthMask(true); - if (r_showdisabledepthtest.integer) - { - qglDepthFunc(GL_ALWAYS);CHECKGLERROR - } GL_BlendFunc(GL_ONE, GL_ZERO); R_Mesh_ColorPointer(NULL); R_Mesh_ResetTextureState(); @@ -3752,9 +3934,5 @@ void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces) } } rsurface_texture = NULL; - if (r_showdisabledepthtest.integer) - { - qglDepthFunc(GL_LEQUAL);CHECKGLERROR - } } }